1 /* TODO for the cases where one just can not autodetect whether header digest
2 is used or not we might need a new preference
10 * Routines for iSCSI dissection
11 * Copyright 2001, Eurologic and Mark Burton <markb@ordern.com>
12 * 2004 Request/Response matching and Service Response Time: ronnie sahlberg
14 * Wireshark - Network traffic analyzer
15 * By Gerald Combs <gerald@wireshark.org>
16 * Copyright 1998 Gerald Combs
18 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version 2
21 * of the License, or (at your option) any later version.
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
41 #include <epan/packet.h>
42 #include <epan/prefs.h>
43 #include <epan/conversation.h>
44 #include "packet-scsi.h"
45 #include <epan/wmem/wmem.h>
46 #include <epan/range.h>
47 #include <wsutil/crc32.h>
49 void proto_register_iscsi(void);
50 void proto_reg_handoff_iscsi(void);
52 /* the absolute values of these constants don't matter as long as
53 * latter revisions of the protocol are assigned a larger number */
54 #define ISCSI_PROTOCOL_DRAFT08 1
55 #define ISCSI_PROTOCOL_DRAFT09 2
56 #define ISCSI_PROTOCOL_DRAFT11 3
57 #define ISCSI_PROTOCOL_DRAFT12 4
58 #define ISCSI_PROTOCOL_DRAFT13 5
60 static const enum_val_t iscsi_protocol_versions[] = {
61 { "draft-08", "Draft 08", ISCSI_PROTOCOL_DRAFT08 },
62 { "draft-09", "Draft 09", ISCSI_PROTOCOL_DRAFT09 },
63 { "draft-11", "Draft 11", ISCSI_PROTOCOL_DRAFT11 },
64 { "draft-12", "Draft 12", ISCSI_PROTOCOL_DRAFT12 },
65 { "draft-13", "Draft 13", ISCSI_PROTOCOL_DRAFT13 },
69 static const value_string ahs_type_vals[] = {
71 {2, "Expected Bidirection Read Data Length"},
75 static dissector_handle_t iscsi_handle=NULL;
77 static gint iscsi_protocol_version = ISCSI_PROTOCOL_DRAFT13;
79 static gboolean iscsi_desegment = TRUE;
81 static int demand_good_f_bit = FALSE;
82 static int enable_bogosity_filter = TRUE;
83 static guint32 bogus_pdu_data_length_threshold = 256 * 1024;
85 static int enableDataDigests = FALSE;
87 static int dataDigestIsCRC32 = TRUE;
89 static guint dataDigestSize = 4;
91 #define TCP_PORT_ISCSI_RANGE "3260"
93 static range_t *global_iscsi_port_range;
94 static guint iscsi_system_port = 860;
96 /* Initialize the protocol and registered fields */
97 static int proto_iscsi = -1;
98 static int hf_iscsi_time = -1;
99 static int hf_iscsi_request_frame = -1;
100 static int hf_iscsi_data_in_frame = -1;
101 static int hf_iscsi_data_out_frame = -1;
102 static int hf_iscsi_response_frame = -1;
103 static int hf_iscsi_AHS_length = -1;
104 static int hf_iscsi_AHS_type = -1;
105 static int hf_iscsi_AHS_blob = -1;
106 static int hf_iscsi_AHS_read_data_length = -1;
107 static int hf_iscsi_AHS_extended_cdb = -1;
108 static int hf_iscsi_Padding = -1;
109 static int hf_iscsi_ping_data = -1;
110 static int hf_iscsi_immediate_data = -1;
111 static int hf_iscsi_async_event_data = -1;
112 static int hf_iscsi_vendor_specific_data = -1;
113 static int hf_iscsi_Opcode = -1;
114 static int hf_iscsi_Flags = -1;
115 static int hf_iscsi_HeaderDigest32 = -1;
116 static int hf_iscsi_DataDigest = -1;
117 static int hf_iscsi_DataDigest32 = -1;
119 static int hf_iscsi_X = -1;
121 static int hf_iscsi_I = -1;
122 static int hf_iscsi_SCSICommand_F = -1;
123 static int hf_iscsi_SCSICommand_R = -1;
124 static int hf_iscsi_SCSICommand_W = -1;
125 static int hf_iscsi_SCSICommand_Attr = -1;
126 static int hf_iscsi_SCSICommand_CRN = -1;
127 static int hf_iscsi_DataSegmentLength = -1;
128 static int hf_iscsi_TotalAHSLength = -1;
129 static int hf_iscsi_InitiatorTaskTag = -1;
130 static int hf_iscsi_ExpectedDataTransferLength = -1;
131 static int hf_iscsi_CmdSN = -1;
132 static int hf_iscsi_ExpStatSN = -1;
133 static int hf_iscsi_StatSN = -1;
134 static int hf_iscsi_ExpCmdSN = -1;
135 static int hf_iscsi_MaxCmdSN = -1;
136 static int hf_iscsi_SCSIResponse_o = -1;
137 static int hf_iscsi_SCSIResponse_u = -1;
138 static int hf_iscsi_SCSIResponse_O = -1;
139 static int hf_iscsi_SCSIResponse_U = -1;
140 static int hf_iscsi_SCSIResponse_BidiReadResidualCount = -1;
141 static int hf_iscsi_SCSIResponse_ResidualCount = -1;
142 static int hf_iscsi_SCSIResponse_Response = -1;
143 static int hf_iscsi_SCSIResponse_Status = -1;
144 static int hf_iscsi_SenseLength = -1;
145 static int hf_iscsi_SCSIData_F = -1;
146 static int hf_iscsi_SCSIData_A = -1;
147 static int hf_iscsi_SCSIData_S = -1;
148 static int hf_iscsi_SCSIData_O = -1;
149 static int hf_iscsi_SCSIData_U = -1;
150 static int hf_iscsi_TargetTransferTag = -1;
151 static int hf_iscsi_DataSN = -1;
152 static int hf_iscsi_BufferOffset = -1;
153 static int hf_iscsi_SCSIData_ResidualCount = -1;
154 static int hf_iscsi_VersionMin = -1;
155 static int hf_iscsi_VersionMax = -1;
156 static int hf_iscsi_VersionActive = -1;
157 static int hf_iscsi_CID = -1;
158 static int hf_iscsi_ISID8 = -1;
159 static int hf_iscsi_ISID = -1;
160 /* #if defined(DRAFT09) */
161 static int hf_iscsi_ISID_Type = -1;
162 static int hf_iscsi_ISID_NamingAuthority = -1;
163 static int hf_iscsi_ISID_Qualifier = -1;
164 /* #elif !defined(DRAFT08) */
165 static int hf_iscsi_ISID_t = -1;
166 static int hf_iscsi_ISID_a = -1;
167 static int hf_iscsi_ISID_b = -1;
168 static int hf_iscsi_ISID_c = -1;
169 static int hf_iscsi_ISID_d = -1;
171 static int hf_iscsi_TSID = -1;
172 static int hf_iscsi_TSIH = -1;
174 static int hf_iscsi_Login_X = -1;
176 static int hf_iscsi_Login_C = -1;
177 static int hf_iscsi_Login_T = -1;
178 static int hf_iscsi_Login_CSG = -1;
179 static int hf_iscsi_Login_NSG = -1;
180 static int hf_iscsi_Login_Status = -1;
181 static int hf_iscsi_KeyValue = -1;
182 static int hf_iscsi_Text_C = -1;
183 static int hf_iscsi_Text_F = -1;
184 static int hf_iscsi_ExpDataSN = -1;
185 static int hf_iscsi_R2TSN = -1;
186 static int hf_iscsi_TaskManagementFunction_ReferencedTaskTag = -1;
187 static int hf_iscsi_RefCmdSN = -1;
188 static int hf_iscsi_TaskManagementFunction_Function = -1;
189 static int hf_iscsi_TaskManagementFunction_Response = -1;
190 static int hf_iscsi_Logout_Reason = -1;
191 static int hf_iscsi_Logout_Response = -1;
192 static int hf_iscsi_Time2Wait = -1;
193 static int hf_iscsi_Time2Retain = -1;
194 static int hf_iscsi_DesiredDataLength = -1;
195 static int hf_iscsi_AsyncEvent = -1;
196 static int hf_iscsi_EventVendorCode = -1;
197 static int hf_iscsi_Parameter1 = -1;
198 static int hf_iscsi_Parameter2 = -1;
199 static int hf_iscsi_Parameter3 = -1;
200 static int hf_iscsi_Reject_Reason = -1;
201 static int hf_iscsi_snack_type = -1;
202 static int hf_iscsi_BegRun = -1;
203 static int hf_iscsi_RunLength = -1;
205 /* Initialize the subtree pointers */
206 static gint ett_iscsi = -1;
207 static gint ett_iscsi_KeyValues = -1;
208 static gint ett_iscsi_CDB = -1;
209 static gint ett_iscsi_Flags = -1;
210 static gint ett_iscsi_RejectHeader = -1;
211 static gint ett_iscsi_lun = -1;
212 /* #ifndef DRAFT08 */
213 static gint ett_iscsi_ISID = -1;
216 #define ISCSI_HEADER_DIGEST_AUTO 0
217 #define ISCSI_HEADER_DIGEST_NONE 1
218 #define ISCSI_HEADER_DIGEST_CRC32 2
219 /* this structure contains session wide state for a specific tcp conversation */
220 typedef struct _iscsi_session_t {
221 guint32 header_digest;
222 wmem_map_t *itlq; /* indexed by ITT */
223 wmem_map_t *itl; /* indexed by LUN */
234 #define OPCODE_MASK 0x3f
236 #define TARGET_OPCODE_BIT 0x20
238 #define ISCSI_OPCODE_NOP_OUT 0x00
239 #define ISCSI_OPCODE_SCSI_COMMAND 0x01
240 #define ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION 0x02
241 #define ISCSI_OPCODE_LOGIN_COMMAND 0x03
242 #define ISCSI_OPCODE_TEXT_COMMAND 0x04
243 #define ISCSI_OPCODE_SCSI_DATA_OUT 0x05
244 #define ISCSI_OPCODE_LOGOUT_COMMAND 0x06
245 #define ISCSI_OPCODE_SNACK_REQUEST 0x10
246 #define ISCSI_OPCODE_VENDOR_SPECIFIC_I0 0x1c
247 #define ISCSI_OPCODE_VENDOR_SPECIFIC_I1 0x1d
248 #define ISCSI_OPCODE_VENDOR_SPECIFIC_I2 0x1e
250 #define ISCSI_OPCODE_NOP_IN 0x20
251 #define ISCSI_OPCODE_SCSI_RESPONSE 0x21
252 #define ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE 0x22
253 #define ISCSI_OPCODE_LOGIN_RESPONSE 0x23
254 #define ISCSI_OPCODE_TEXT_RESPONSE 0x24
255 #define ISCSI_OPCODE_SCSI_DATA_IN 0x25
256 #define ISCSI_OPCODE_LOGOUT_RESPONSE 0x26
257 #define ISCSI_OPCODE_R2T 0x31
258 #define ISCSI_OPCODE_ASYNC_MESSAGE 0x32
259 #define ISCSI_OPCODE_REJECT 0x3f
260 #define ISCSI_OPCODE_VENDOR_SPECIFIC_T0 0x3c
261 #define ISCSI_OPCODE_VENDOR_SPECIFIC_T1 0x3d
262 #define ISCSI_OPCODE_VENDOR_SPECIFIC_T2 0x3e
265 #define CSG_MASK (0x03 << CSG_SHIFT)
266 #define NSG_MASK 0x03
268 #define ISCSI_CSG_SECURITY_NEGOTIATION (0 << CSG_SHIFT)
269 #define ISCSI_CSG_OPERATIONAL_NEGOTIATION (1 << CSG_SHIFT)
270 #define ISCSI_CSG_FULL_FEATURE_PHASE (3 << CSG_SHIFT)
272 #define ISCSI_SCSI_DATA_FLAG_S 0x01
273 #define ISCSI_SCSI_DATA_FLAG_U 0x02
274 #define ISCSI_SCSI_DATA_FLAG_O 0x04
275 #define ISCSI_SCSI_DATA_FLAG_A 0x40
276 #define ISCSI_SCSI_DATA_FLAG_F 0x80
278 static const value_string iscsi_opcodes[] = {
279 { ISCSI_OPCODE_NOP_OUT, "NOP Out" },
280 { ISCSI_OPCODE_SCSI_COMMAND, "SCSI Command" },
281 { ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION, "Task Management Function" },
282 { ISCSI_OPCODE_LOGIN_COMMAND, "Login Command" },
283 { ISCSI_OPCODE_TEXT_COMMAND, "Text Command" },
284 { ISCSI_OPCODE_SCSI_DATA_OUT, "SCSI Data Out" },
285 { ISCSI_OPCODE_LOGOUT_COMMAND, "Logout Command" },
286 { ISCSI_OPCODE_SNACK_REQUEST, "SNACK Request" },
287 { ISCSI_OPCODE_VENDOR_SPECIFIC_I0, "Vendor Specific I0" },
288 { ISCSI_OPCODE_VENDOR_SPECIFIC_I1, "Vendor Specific I1" },
289 { ISCSI_OPCODE_VENDOR_SPECIFIC_I2, "Vendor Specific I2" },
291 { ISCSI_OPCODE_NOP_IN, "NOP In" },
292 { ISCSI_OPCODE_SCSI_RESPONSE, "SCSI Response" },
293 { ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE, "Task Management Function Response" },
294 { ISCSI_OPCODE_LOGIN_RESPONSE, "Login Response" },
295 { ISCSI_OPCODE_TEXT_RESPONSE, "Text Response" },
296 { ISCSI_OPCODE_SCSI_DATA_IN, "SCSI Data In" },
297 { ISCSI_OPCODE_LOGOUT_RESPONSE, "Logout Response" },
298 { ISCSI_OPCODE_R2T, "Ready To Transfer" },
299 { ISCSI_OPCODE_ASYNC_MESSAGE, "Asynchronous Message" },
300 { ISCSI_OPCODE_REJECT, "Reject"},
301 { ISCSI_OPCODE_VENDOR_SPECIFIC_T0, "Vendor Specific T0" },
302 { ISCSI_OPCODE_VENDOR_SPECIFIC_T1, "Vendor Specific T1" },
303 { ISCSI_OPCODE_VENDOR_SPECIFIC_T2, "Vendor Specific T2" },
308 static const true_false_string iscsi_meaning_X = {
315 static const true_false_string iscsi_meaning_login_X = {
316 "Reinstate failed connection",
321 static const true_false_string iscsi_meaning_I = {
322 "Immediate delivery",
326 static const true_false_string iscsi_meaning_F = {
327 "Final PDU in sequence",
328 "Not final PDU in sequence"
331 static const true_false_string iscsi_meaning_A = {
332 "Acknowledge requested",
333 "Acknowledge not requested"
336 static const true_false_string iscsi_meaning_T = {
337 "Transit to next login stage",
338 "Stay in current login stage"
341 static const true_false_string iscsi_meaning_C = {
342 "Text is incomplete",
346 static const true_false_string iscsi_meaning_S = {
347 "Response contains SCSI status",
348 "Response does not contain SCSI status"
351 static const true_false_string iscsi_meaning_R = {
352 "Data will be read from target",
353 "No data will be read from target"
356 static const true_false_string iscsi_meaning_W = {
357 "Data will be written to target",
358 "No data will be written to target"
361 static const true_false_string iscsi_meaning_o = {
362 "Read part of bi-directional command overflowed",
363 "No overflow of read part of bi-directional command",
366 static const true_false_string iscsi_meaning_u = {
367 "Read part of bi-directional command underflowed",
368 "No underflow of read part of bi-directional command",
371 static const true_false_string iscsi_meaning_O = {
372 "Residual overflow occurred",
373 "No residual overflow occurred",
376 static const true_false_string iscsi_meaning_U = {
377 "Residual underflow occurred",
378 "No residual underflow occurred",
381 static const value_string iscsi_scsi_responses[] = {
382 { 0, "Command completed at target" },
383 { 1, "Response does not contain SCSI status"},
387 static const value_string iscsi_scsicommand_taskattrs[] = {
391 {3, "Head of Queue"},
396 static const value_string iscsi_task_management_responses[] = {
397 {0, "Function complete"},
398 {1, "Task not in task set"},
399 {2, "LUN does not exist"},
400 {3, "Task still allegiant"},
401 {4, "Task failover not supported"},
402 {5, "Task management function not supported"},
403 {6, "Authorisation failed"},
404 {255, "Function rejected"},
408 static const value_string iscsi_task_management_functions[] = {
410 {2, "Abort Task Set"},
412 {4, "Clear Task Set"},
413 {5, "Logical Unit Reset"},
414 {6, "Target Warm Reset"},
415 {7, "Target Cold Reset"},
416 {8, "Target Reassign"},
420 static const value_string iscsi_login_status[] = {
422 {0x0101, "Target moved temporarily"},
423 {0x0102, "Target moved permanently"},
424 {0x0200, "Initiator error (miscellaneous error)"},
425 {0x0201, "Authentication failed"},
426 {0x0202, "Authorisation failure"},
427 {0x0203, "Target not found"},
428 {0x0204, "Target removed"},
429 {0x0205, "Unsupported version"},
430 {0x0206, "Too many connections"},
431 {0x0207, "Missing parameter"},
432 {0x0208, "Can't include in session"},
433 {0x0209, "Session type not supported"},
434 {0x020a, "Session does not exist"},
435 {0x020b, "Invalid request during login"},
436 {0x0300, "Target error (miscellaneous error)"},
437 {0x0301, "Service unavailable"},
438 {0x0302, "Out of resources"},
442 static const value_string iscsi_login_stage[] = {
443 {0, "Security negotiation"},
444 {1, "Operational negotiation"},
445 {3, "Full feature phase"},
449 /* #ifndef DRAFT08 */
450 static const value_string iscsi_isid_type[] = {
452 {0x01, "IANA Enterprise Number"},
458 static const value_string iscsi_logout_reasons[] = {
459 {0, "Close session"},
460 {1, "Close connection"},
461 {2, "Remove connection for recovery"},
465 static const value_string iscsi_logout_response[] = {
466 {0, "Connection closed successfully"},
467 {1, "CID not found"},
468 {2, "Connection recovery not supported"},
469 {3, "Cleanup failed for various reasons"},
473 static const value_string iscsi_asyncevents[] = {
474 {0, "A SCSI asynchronous event is reported in the sense data"},
475 {1, "Target requests logout"},
476 {2, "Target will/has dropped connection"},
477 {3, "Target will/has dropped all connections"},
478 {4, "Target requests parameter negotiation"},
482 static const value_string iscsi_snack_types[] = {
485 /* #ifndef DRAFT08 */
492 static const value_string iscsi_reject_reasons[] = {
494 {0x01, "Full feature phase command before login"},
496 {0x02, "Data (payload) digest error"},
497 {0x03, "Data SNACK reject"},
498 {0x04, "Protocol error"},
499 {0x05, "Command not supported in this session type"},
500 {0x06, "Immediate command reject (too many immediate commands)"},
501 {0x07, "Task in progress"},
502 {0x08, "Invalid Data Ack"},
503 {0x09, "Invalid PDU field"},
504 {0x0a, "Long operation reject"},
505 {0x0b, "Negotiation reset"},
506 {0x0c, "Waiting for logout"},
510 /* structure and functions to keep track of
511 * COMMAND/DATA_IN/DATA_OUT/RESPONSE matching
513 typedef struct _iscsi_conv_data {
514 guint32 data_in_frame;
515 guint32 data_out_frame;
519 /* TargetAddress describes a iscsi port, possibly using a non-standard port
520 so we can use this to set up a conversation dissector to that port.
522 TargetAddress is of the form :
523 TargetAddress=domainname[:port][,portal-group-tag]
525 where domainname is either a dns-name, an ipv4 address is dotted-decimal
526 form or a bracketed ipv6 address.
527 so treat this as signalling, parse the value and register iscis as a conversation
528 dissector for the address/port that TargetAddress points to.
529 (it starts to be common to use redirectors to point to non-3260 ports)
532 iscsi_dissect_TargetAddress(packet_info *pinfo, proto_tree *tree _U_,char *val)
534 address *addr = NULL;
536 char *value = wmem_strdup(wmem_packet_scope(), val);
537 char *p = NULL, *pgt = NULL;
539 if (value[0] == '[') {
540 /* this looks like an ipv6 address */
541 p = strchr(value, ']');
544 p += 2; /* skip past "]:" */
546 pgt = strchr(p, ',');
551 /* cant handle ipv6 yet */
554 /* This is either a ipv4 address or a dns name */
556 if (sscanf(value, "%d.%d.%d.%d", &i0,&i1,&i2,&i3) == 4) {
557 /* looks like a ipv4 address */
558 p = strchr(value, ':');
564 pgt = strchr(p, ',');
569 addr_data = (char *) wmem_alloc(wmem_packet_scope(), 4);
575 addr = wmem_new(wmem_packet_scope(), address);
576 addr->type = AT_IPv4;
578 addr->data = addr_data;
587 /* attach a conversation dissector to this address/port tuple */
588 if (addr && !pinfo->fd->flags.visited) {
589 conversation_t *conv;
591 conv = conversation_new(pinfo->fd->num, addr, addr, PT_TCP, port, port, NO_ADDR2|NO_PORT2);
595 conversation_set_dissector(conv, iscsi_handle);
601 addTextKeys(packet_info *pinfo, proto_tree *tt, tvbuff_t *tvb, gint offset, guint32 text_len) {
602 const gint limit = offset + text_len;
604 while(offset < limit) {
605 char *key = NULL, *value = NULL;
606 gint len = tvb_strnlen(tvb, offset, limit - offset);
609 len = limit - offset;
614 key = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, len, ENC_ASCII);
618 value = strchr(key, '=');
624 if (!strcmp(key, "TargetAddress")) {
625 iscsi_dissect_TargetAddress(pinfo, tt, value);
628 proto_tree_add_item(tt, hf_iscsi_KeyValue, tvb, offset, len, ENC_ASCII|ENC_NA);
635 handleHeaderDigest(iscsi_session_t *iscsi_session, proto_item *ti, tvbuff_t *tvb, guint offset, int headerLen) {
636 int available_bytes = tvb_length_remaining(tvb, offset);
638 switch(iscsi_session->header_digest){
639 case ISCSI_HEADER_DIGEST_CRC32:
640 if(available_bytes >= (headerLen + 4)) {
641 guint32 crc = ~crc32c_calculate(tvb_get_ptr(tvb, offset, headerLen), headerLen, CRC32C_PRELOAD);
642 guint32 sent = tvb_get_ntohl(tvb, offset + headerLen);
644 proto_tree_add_uint_format_value(ti, hf_iscsi_HeaderDigest32, tvb, offset + headerLen, 4, sent, "0x%08x (Good CRC32)", sent);
646 proto_tree_add_uint_format_value(ti, hf_iscsi_HeaderDigest32, tvb, offset + headerLen, 4, sent, "0x%08x (Bad CRC32, should be 0x%08x)", sent, crc);
649 return offset + headerLen + 4;
651 return offset + headerLen;
655 handleDataDigest(proto_item *ti, tvbuff_t *tvb, guint offset, int dataLen) {
656 int available_bytes = tvb_length_remaining(tvb, offset);
657 if(enableDataDigests) {
658 if(dataDigestIsCRC32) {
659 if(available_bytes >= (dataLen + 4)) {
660 guint32 crc = ~crc32c_calculate(tvb_get_ptr(tvb, offset, dataLen), dataLen, CRC32C_PRELOAD);
661 guint32 sent = tvb_get_ntohl(tvb, offset + dataLen);
663 proto_tree_add_uint_format_value(ti, hf_iscsi_DataDigest32, tvb, offset + dataLen, 4, sent, "0x%08x (Good CRC32)", sent);
666 proto_tree_add_uint_format_value(ti, hf_iscsi_DataDigest32, tvb, offset + dataLen, 4, sent, "0x%08x (Bad CRC32, should be 0x%08x)", sent, crc);
669 return offset + dataLen + 4;
671 if((unsigned)available_bytes >= (dataLen + dataDigestSize)) {
672 proto_tree_add_item(ti, hf_iscsi_DataDigest, tvb, offset + dataLen, dataDigestSize, ENC_NA);
674 return offset + dataLen + dataDigestSize;
676 return offset + dataLen;
680 handleDataSegment(proto_item *ti, tvbuff_t *tvb, guint offset, guint dataSegmentLen, guint endOffset, int hf_id) {
681 if(endOffset > offset) {
682 int dataOffset = offset;
683 int dataLen = MIN(dataSegmentLen, endOffset - offset);
685 proto_tree_add_item(ti, hf_id, tvb, offset, dataLen, ENC_NA);
688 if(offset < endOffset && (offset & 3) != 0) {
689 int padding = 4 - (offset & 3);
690 proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, ENC_NA);
693 if(dataSegmentLen > 0 && offset < endOffset)
694 offset = handleDataDigest(ti, tvb, dataOffset, offset - dataOffset);
701 handleDataSegmentAsTextKeys(packet_info *pinfo, proto_item *ti, tvbuff_t *tvb, guint offset, guint dataSegmentLen, guint endOffset, int digestsActive) {
702 if(endOffset > offset) {
703 int dataOffset = offset;
704 int textLen = MIN(dataSegmentLen, endOffset - offset);
706 proto_item *tf = proto_tree_add_text(ti, tvb, offset, textLen, "Key/Value Pairs");
707 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_KeyValues);
708 offset = addTextKeys(pinfo, tt, tvb, offset, textLen);
710 if(offset < endOffset && (offset & 3) != 0) {
711 int padding = 4 - (offset & 3);
712 proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, ENC_NA);
715 if(digestsActive && dataSegmentLen > 0 && offset < endOffset)
716 offset = handleDataDigest(ti, tvb, dataOffset, offset - dataOffset);
721 /* Code to actually dissect the packets */
723 dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 opcode, const char *opcode_str, guint32 data_segment_len, iscsi_session_t *iscsi_session, conversation_t *conversation) {
725 guint original_offset = offset;
726 proto_tree *ti = NULL;
727 guint8 scsi_status = 0;
728 gboolean S_bit=FALSE;
729 gboolean A_bit=FALSE;
730 guint cdb_offset = offset + 32; /* offset of CDB from start of PDU */
731 guint end_offset = offset + tvb_length_remaining(tvb, offset);
732 iscsi_conv_data_t *cdata = NULL;
733 int paddedDataSegmentLength = data_segment_len;
735 guint immediate_data_length=0;
736 guint immediate_data_offset=0;
737 itl_nexus_t *itl=NULL;
738 guint ahs_cdb_length=0;
739 guint ahs_cdb_offset=0;
740 guint32 data_offset=0;
742 if(paddedDataSegmentLength & 3)
743 paddedDataSegmentLength += 4 - (paddedDataSegmentLength & 3);
745 /* Make entries in Protocol column and Info column on summary display */
746 col_set_str(pinfo->cinfo, COL_PROTOCOL, "iSCSI");
748 /* XXX we need a way to handle replayed iscsi itt here */
749 cdata=(iscsi_conv_data_t *)wmem_map_lookup(iscsi_session->itlq, GUINT_TO_POINTER(tvb_get_ntohl(tvb, offset+16)));
751 cdata = wmem_new(wmem_file_scope(), iscsi_conv_data_t);
752 cdata->itlq.lun=0xffff;
753 cdata->itlq.scsi_opcode=0xffff;
754 cdata->itlq.task_flags=0;
755 cdata->itlq.data_length=0;
756 cdata->itlq.bidir_data_length=0;
757 cdata->itlq.fc_time = pinfo->fd->abs_ts;
758 cdata->itlq.first_exchange_frame=0;
759 cdata->itlq.last_exchange_frame=0;
761 cdata->itlq.alloc_len=0;
762 cdata->itlq.extra_data=NULL;
763 cdata->data_in_frame=0;
764 cdata->data_out_frame=0;
766 wmem_map_insert(iscsi_session->itlq, GUINT_TO_POINTER(tvb_get_ntohl(tvb, offset+16)), cdata);
769 if (opcode == ISCSI_OPCODE_SCSI_RESPONSE ||
770 opcode == ISCSI_OPCODE_SCSI_DATA_IN) {
771 scsi_status = tvb_get_guint8 (tvb, offset+3);
774 if ((opcode == ISCSI_OPCODE_SCSI_RESPONSE) ||
775 (opcode == ISCSI_OPCODE_SCSI_DATA_IN) ||
776 (opcode == ISCSI_OPCODE_SCSI_DATA_OUT)) {
777 /* first time we see this packet. check if we can find the request */
779 case ISCSI_OPCODE_SCSI_RESPONSE:
780 cdata->itlq.last_exchange_frame=pinfo->fd->num;
782 case ISCSI_OPCODE_SCSI_DATA_IN:
783 /* a bit ugly but we need to check the S bit here */
784 if(tvb_get_guint8(tvb, offset+1)&ISCSI_SCSI_DATA_FLAG_S){
785 cdata->itlq.last_exchange_frame=pinfo->fd->num;
787 cdata->data_in_frame=pinfo->fd->num;
789 case ISCSI_OPCODE_SCSI_DATA_OUT:
790 cdata->data_out_frame=pinfo->fd->num;
794 } else if (opcode == ISCSI_OPCODE_SCSI_COMMAND) {
795 /*we need the LUN value for some of the commands so we can pass it
796 across to the SCSI dissector.
797 Not correct but simple and probably accurate enough :
798 If bit 6 of first bit is 0 then just take second byte as the LUN
799 If bit 6 of first bit is 1, then take 6 bits from first byte
800 and all of second byte and pretend it is the lun value
801 people that care can add host specific dissection of vsa later.
803 We need to keep track of this on a per transaction basis since
804 for error recoverylevel 0 and when the A bit is clear in a
805 Data-In PDU, there will not be a LUN field in teh iscsi layer.
807 if(tvb_get_guint8(tvb, offset+8)&0x40){
808 /* volume set addressing */
809 lun=tvb_get_guint8(tvb,offset+8)&0x3f;
811 lun|=tvb_get_guint8(tvb,offset+9);
813 lun=tvb_get_guint8(tvb,offset+9);
817 cdata->itlq.first_exchange_frame=pinfo->fd->num;
819 itl=(itl_nexus_t *)wmem_map_lookup(iscsi_session->itl, GUINT_TO_POINTER((gulong)lun));
821 itl=wmem_new(wmem_file_scope(), itl_nexus_t);
823 itl->conversation=conversation;
824 wmem_map_insert(iscsi_session->itl, GUINT_TO_POINTER((gulong)lun), itl);
830 itl=(itl_nexus_t *)wmem_map_lookup(iscsi_session->itl, GUINT_TO_POINTER((gulong)cdata->itlq.lun));
835 if (opcode != ISCSI_OPCODE_SCSI_COMMAND) {
837 col_append_str(pinfo->cinfo, COL_INFO, opcode_str);
839 if (opcode == ISCSI_OPCODE_SCSI_RESPONSE ||
840 (opcode == ISCSI_OPCODE_SCSI_DATA_IN &&
841 (tvb_get_guint8(tvb, offset + 1) & ISCSI_SCSI_DATA_FLAG_S))) {
842 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
843 val_to_str (scsi_status, scsi_status_val, "0x%x"));
845 else if (opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
846 guint16 login_status = tvb_get_ntohs(tvb, offset+36);
847 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
848 val_to_str (login_status, iscsi_login_status, "0x%x"));
850 else if (opcode == ISCSI_OPCODE_LOGOUT_COMMAND) {
852 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
853 logoutReason = tvb_get_guint8(tvb, offset+11);
854 } else if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
855 logoutReason = tvb_get_guint8(tvb, offset+1) & 0x7f;
858 logoutReason = tvb_get_guint8(tvb, offset+23);
860 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
861 val_to_str (logoutReason, iscsi_logout_reasons, "0x%x"));
863 else if (opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION) {
864 guint8 tmf = tvb_get_guint8(tvb, offset + 1) & 0x7f;
865 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
866 val_to_str (tmf, iscsi_task_management_functions, "0x%x"));
868 else if (opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE) {
869 guint8 resp = tvb_get_guint8(tvb, offset + 2);
870 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
871 val_to_str (resp, iscsi_task_management_responses, "0x%x"));
873 else if (opcode == ISCSI_OPCODE_REJECT) {
874 guint8 reason = tvb_get_guint8(tvb, offset + 2);
875 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
876 val_to_str (reason, iscsi_reject_reasons, "0x%x"));
878 else if (opcode == ISCSI_OPCODE_ASYNC_MESSAGE) {
879 guint8 asyncEvent = tvb_get_guint8(tvb, offset + 36);
880 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
881 val_to_str (asyncEvent, iscsi_asyncevents, "0x%x"));
885 /* In the interest of speed, if "tree" is NULL, don't do any
886 work not necessary to generate protocol tree items. */
889 /* create display subtree for the protocol */
890 tp = proto_tree_add_protocol_format(tree, proto_iscsi, tvb,
891 offset, -1, "iSCSI (%s)",
893 ti = proto_item_add_subtree(tp, ett_iscsi);
895 proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb,
896 offset + 0, 1, opcode);
897 if((opcode & TARGET_OPCODE_BIT) == 0) {
898 /* initiator -> target */
899 gint b = tvb_get_guint8(tvb, offset + 0);
900 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
901 if(opcode != ISCSI_OPCODE_SCSI_DATA_OUT &&
902 opcode != ISCSI_OPCODE_LOGOUT_COMMAND &&
903 opcode != ISCSI_OPCODE_SNACK_REQUEST)
904 proto_tree_add_boolean(ti, hf_iscsi_X, tvb, offset + 0, 1, b);
906 if(opcode != ISCSI_OPCODE_SCSI_DATA_OUT &&
907 opcode != ISCSI_OPCODE_LOGIN_COMMAND &&
908 opcode != ISCSI_OPCODE_SNACK_REQUEST)
909 proto_tree_add_boolean(ti, hf_iscsi_I, tvb, offset + 0, 1, b);
912 if(opcode == ISCSI_OPCODE_NOP_OUT) {
914 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
915 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
917 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, tvb_get_ntoh24(tvb, offset + 5));
918 dissect_scsi_lun(ti, tvb, offset + 8);
919 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, ENC_BIG_ENDIAN);
920 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, ENC_BIG_ENDIAN);
921 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, ENC_BIG_ENDIAN);
922 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, ENC_BIG_ENDIAN);
923 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
924 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_ping_data);
925 } else if(opcode == ISCSI_OPCODE_NOP_IN) {
927 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
928 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
930 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, tvb_get_ntoh24(tvb, offset + 5));
931 dissect_scsi_lun(ti, tvb, offset + 8);
932 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, ENC_BIG_ENDIAN);
933 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, ENC_BIG_ENDIAN);
934 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, ENC_BIG_ENDIAN);
935 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, ENC_BIG_ENDIAN);
936 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, ENC_BIG_ENDIAN);
937 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
938 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_ping_data);
939 } else if(opcode == ISCSI_OPCODE_SCSI_COMMAND) {
941 guint32 ahsLen = tvb_get_guint8(tvb, offset + 4) * 4;
943 gint b = tvb_get_guint8(tvb, offset + 1);
945 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
946 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
948 proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_F, tvb, offset + 1, 1, b);
949 proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_R, tvb, offset + 1, 1, b);
951 cdata->itlq.task_flags|=SCSI_DATA_READ;
953 proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_W, tvb, offset + 1, 1, b);
955 cdata->itlq.task_flags|=SCSI_DATA_WRITE;
957 proto_tree_add_uint(tt, hf_iscsi_SCSICommand_Attr, tvb, offset + 1, 1, b);
959 if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT12) {
960 proto_tree_add_item(ti, hf_iscsi_SCSICommand_CRN, tvb, offset + 3, 1, ENC_BIG_ENDIAN);
962 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
963 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, tvb_get_ntoh24(tvb, offset + 5));
964 dissect_scsi_lun(ti, tvb, offset + 8);
965 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, ENC_BIG_ENDIAN);
966 proto_tree_add_item(ti, hf_iscsi_ExpectedDataTransferLength, tvb, offset + 20, 4, ENC_BIG_ENDIAN);
967 cdata->itlq.data_length=tvb_get_ntohl(tvb, offset+20);
968 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, ENC_BIG_ENDIAN);
969 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, ENC_BIG_ENDIAN);
971 guint ahs_offset=offset+48;
972 guint16 ahs_length=0;
975 while(ahs_offset<(offset+48+ahsLen)){
977 ahs_length=tvb_get_ntohs(tvb, ahs_offset);
978 proto_tree_add_item(ti, hf_iscsi_AHS_length, tvb, ahs_offset, 2, ENC_BIG_ENDIAN);
981 ahs_type=tvb_get_guint8(tvb, ahs_offset);
982 proto_tree_add_item(ti, hf_iscsi_AHS_type, tvb, ahs_offset, 1, ENC_BIG_ENDIAN);
986 case 0x01: /* extended CDB */
988 ahs_cdb_offset=ahs_offset+1;
989 ahs_cdb_length=ahs_length-1;
990 proto_tree_add_item(ti, hf_iscsi_AHS_extended_cdb, tvb, ahs_cdb_offset, ahs_cdb_length, ENC_NA);
991 ahs_offset+=ahs_length;
993 case 0x02: /* bidirectional read data length */
994 /* skip reserved byte */
996 /* read data length */
997 proto_tree_add_item(ti, hf_iscsi_AHS_read_data_length, tvb, ahs_offset, 4, ENC_BIG_ENDIAN);
998 cdata->itlq.bidir_data_length=tvb_get_ntohl(tvb, ahs_offset);
1002 proto_tree_add_item(ti, hf_iscsi_AHS_blob, tvb, ahs_offset, ahs_length, ENC_NA);
1003 ahs_offset+=ahs_length;
1006 /* strip off padding bytes */
1008 ahs_offset=(ahs_offset+3) & ~3;
1014 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48 + ahsLen);
1016 immediate_data_offset=offset;
1017 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_immediate_data);
1018 immediate_data_length=offset-immediate_data_offset;
1019 } else if(opcode == ISCSI_OPCODE_SCSI_RESPONSE) {
1022 gint b = tvb_get_guint8(tvb, offset + 1);
1023 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1024 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1026 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_o, tvb, offset + 1, 1, b);
1027 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_u, tvb, offset + 1, 1, b);
1028 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_O, tvb, offset + 1, 1, b);
1029 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_U, tvb, offset + 1, 1, b);
1031 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Response, tvb, offset + 2, 1, ENC_BIG_ENDIAN);
1032 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Status, tvb, offset + 3, 1, ENC_BIG_ENDIAN);
1033 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1034 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
1036 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, tvb_get_ntoh24(tvb, offset + 5));
1037 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, ENC_BIG_ENDIAN);
1038 if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
1039 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_ResidualCount, tvb, offset + 20, 4, ENC_BIG_ENDIAN);
1041 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, ENC_BIG_ENDIAN);
1042 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, ENC_BIG_ENDIAN);
1043 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, ENC_BIG_ENDIAN);
1044 proto_tree_add_item(ti, hf_iscsi_ExpDataSN, tvb, offset + 36, 4, ENC_BIG_ENDIAN);
1045 if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
1046 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_BidiReadResidualCount, tvb, offset + 44, 4, ENC_BIG_ENDIAN);
1049 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_BidiReadResidualCount, tvb, offset + 40, 4, ENC_BIG_ENDIAN);
1050 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_ResidualCount, tvb, offset + 44, 4, ENC_BIG_ENDIAN);
1052 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1053 /* do not update offset here because the data segment is
1054 * dissected below */
1055 handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
1056 } else if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION) {
1057 /* Task Management Function */
1058 proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_Function, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
1059 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1060 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
1061 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, tvb_get_ntoh24(tvb, offset + 5));
1063 dissect_scsi_lun(ti, tvb, offset + 8);
1064 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, ENC_BIG_ENDIAN);
1065 proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_ReferencedTaskTag, tvb, offset + 20, 4, ENC_BIG_ENDIAN);
1066 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, ENC_BIG_ENDIAN);
1067 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, ENC_BIG_ENDIAN);
1068 proto_tree_add_item(ti, hf_iscsi_RefCmdSN, tvb, offset + 32, 4, ENC_BIG_ENDIAN);
1069 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1070 } else if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE) {
1071 /* Task Management Function Response */
1072 proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_Response, tvb, offset + 2, 1, ENC_BIG_ENDIAN);
1073 if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
1074 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
1075 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, tvb_get_ntoh24(tvb, offset + 5));
1077 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, ENC_BIG_ENDIAN);
1078 if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT12) {
1079 proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_ReferencedTaskTag, tvb, offset + 20, 4, ENC_BIG_ENDIAN);
1081 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, ENC_BIG_ENDIAN);
1082 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, ENC_BIG_ENDIAN);
1083 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, ENC_BIG_ENDIAN);
1084 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1085 } else if(opcode == ISCSI_OPCODE_LOGIN_COMMAND) {
1087 int digestsActive = 0;
1089 gint b = tvb_get_guint8(tvb, offset + 1);
1090 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1091 if((b & CSG_MASK) >= ISCSI_CSG_OPERATIONAL_NEGOTIATION)
1095 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1096 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1099 proto_tree_add_boolean(ti, hf_iscsi_Login_T, tvb, offset + 1, 1, b);
1100 if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1101 proto_tree_add_boolean(ti, hf_iscsi_Login_C, tvb, offset + 1, 1, b);
1103 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1104 proto_tree_add_boolean(ti, hf_iscsi_Login_X, tvb, offset + 1, 1, b);
1106 proto_tree_add_item(ti, hf_iscsi_Login_CSG, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
1108 /* NSG is undefined unless T is set */
1110 proto_tree_add_item(ti, hf_iscsi_Login_NSG, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
1113 proto_tree_add_item(ti, hf_iscsi_VersionMax, tvb, offset + 2, 1, ENC_BIG_ENDIAN);
1114 proto_tree_add_item(ti, hf_iscsi_VersionMin, tvb, offset + 3, 1, ENC_BIG_ENDIAN);
1115 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1116 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
1118 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, tvb_get_ntoh24(tvb, offset + 5));
1119 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1120 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 8, 2, ENC_BIG_ENDIAN);
1121 proto_tree_add_item(ti, hf_iscsi_ISID8, tvb, offset + 12, 2, ENC_BIG_ENDIAN);
1124 proto_item *tf = proto_tree_add_item(ti, hf_iscsi_ISID, tvb, offset + 8, 6, ENC_NA);
1125 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_ISID);
1126 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT09) {
1127 proto_tree_add_item(tt, hf_iscsi_ISID_Type, tvb, offset + 8, 1, ENC_BIG_ENDIAN);
1128 proto_tree_add_item(tt, hf_iscsi_ISID_NamingAuthority, tvb, offset + 9, 3, ENC_BIG_ENDIAN);
1129 proto_tree_add_item(tt, hf_iscsi_ISID_Qualifier, tvb, offset + 12, 2, ENC_BIG_ENDIAN);
1132 proto_tree_add_item(tt, hf_iscsi_ISID_t, tvb, offset + 8, 1, ENC_BIG_ENDIAN);
1133 proto_tree_add_item(tt, hf_iscsi_ISID_a, tvb, offset + 8, 1, ENC_BIG_ENDIAN);
1134 proto_tree_add_item(tt, hf_iscsi_ISID_b, tvb, offset + 9, 2, ENC_BIG_ENDIAN);
1135 proto_tree_add_item(tt, hf_iscsi_ISID_c, tvb, offset + 11, 1, ENC_BIG_ENDIAN);
1136 proto_tree_add_item(tt, hf_iscsi_ISID_d, tvb, offset + 12, 2, ENC_BIG_ENDIAN);
1139 if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT12) {
1140 proto_tree_add_item(ti, hf_iscsi_TSID, tvb, offset + 14, 2, ENC_BIG_ENDIAN);
1143 proto_tree_add_item(ti, hf_iscsi_TSIH, tvb, offset + 14, 2, ENC_BIG_ENDIAN);
1145 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, ENC_BIG_ENDIAN);
1146 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT08) {
1147 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 20, 2, ENC_BIG_ENDIAN);
1149 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, ENC_BIG_ENDIAN);
1150 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, ENC_BIG_ENDIAN);
1152 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1156 offset = handleDataSegmentAsTextKeys(pinfo, ti, tvb, offset, data_segment_len, end_offset, digestsActive);
1157 } else if(opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
1158 /* Login Response */
1159 int digestsActive = 0;
1161 gint b = tvb_get_guint8(tvb, offset + 1);
1162 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1163 if((b & CSG_MASK) >= ISCSI_CSG_OPERATIONAL_NEGOTIATION)
1167 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1168 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1171 proto_tree_add_boolean(ti, hf_iscsi_Login_T, tvb, offset + 1, 1, b);
1172 if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1173 proto_tree_add_boolean(ti, hf_iscsi_Login_C, tvb, offset + 1, 1, b);
1175 proto_tree_add_item(ti, hf_iscsi_Login_CSG, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
1176 /* NSG is undefined unless T is set */
1178 proto_tree_add_item(ti, hf_iscsi_Login_NSG, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
1182 proto_tree_add_item(ti, hf_iscsi_VersionMax, tvb, offset + 2, 1, ENC_BIG_ENDIAN);
1183 proto_tree_add_item(ti, hf_iscsi_VersionActive, tvb, offset + 3, 1, ENC_BIG_ENDIAN);
1184 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1185 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
1187 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, tvb_get_ntoh24(tvb, offset + 5));
1188 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1189 proto_tree_add_item(ti, hf_iscsi_ISID8, tvb, offset + 12, 2, ENC_BIG_ENDIAN);
1192 proto_item *tf = proto_tree_add_item(ti, hf_iscsi_ISID, tvb, offset + 8, 6, ENC_NA);
1193 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_ISID);
1194 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT09) {
1195 proto_tree_add_item(tt, hf_iscsi_ISID_Type, tvb, offset + 8, 1, ENC_BIG_ENDIAN);
1196 proto_tree_add_item(tt, hf_iscsi_ISID_NamingAuthority, tvb, offset + 9, 3, ENC_BIG_ENDIAN);
1197 proto_tree_add_item(tt, hf_iscsi_ISID_Qualifier, tvb, offset + 12, 2, ENC_BIG_ENDIAN);
1200 proto_tree_add_item(tt, hf_iscsi_ISID_t, tvb, offset + 8, 1, ENC_BIG_ENDIAN);
1201 proto_tree_add_item(tt, hf_iscsi_ISID_a, tvb, offset + 8, 1, ENC_BIG_ENDIAN);
1202 proto_tree_add_item(tt, hf_iscsi_ISID_b, tvb, offset + 9, 2, ENC_BIG_ENDIAN);
1203 proto_tree_add_item(tt, hf_iscsi_ISID_c, tvb, offset + 11, 1, ENC_BIG_ENDIAN);
1204 proto_tree_add_item(tt, hf_iscsi_ISID_d, tvb, offset + 12, 2, ENC_BIG_ENDIAN);
1207 if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT12) {
1208 proto_tree_add_item(ti, hf_iscsi_TSID, tvb, offset + 14, 2, ENC_BIG_ENDIAN);
1211 proto_tree_add_item(ti, hf_iscsi_TSIH, tvb, offset + 14, 2, ENC_BIG_ENDIAN);
1213 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, ENC_BIG_ENDIAN);
1214 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, ENC_BIG_ENDIAN);
1215 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, ENC_BIG_ENDIAN);
1216 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, ENC_BIG_ENDIAN);
1217 proto_tree_add_item(ti, hf_iscsi_Login_Status, tvb, offset + 36, 2, ENC_BIG_ENDIAN);
1219 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1223 offset = handleDataSegmentAsTextKeys(pinfo, ti, tvb, offset, data_segment_len, end_offset, digestsActive);
1224 } else if(opcode == ISCSI_OPCODE_TEXT_COMMAND) {
1227 gint b = tvb_get_guint8(tvb, offset + 1);
1228 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1229 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1231 proto_tree_add_boolean(tt, hf_iscsi_Text_F, tvb, offset + 1, 1, b);
1232 if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1233 proto_tree_add_boolean(tt, hf_iscsi_Text_C, tvb, offset + 1, 1, b);
1236 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1237 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
1239 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, tvb_get_ntoh24(tvb, offset + 5));
1240 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1241 dissect_scsi_lun(ti, tvb, offset + 8);
1243 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, ENC_BIG_ENDIAN);
1244 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, ENC_BIG_ENDIAN);
1245 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, ENC_BIG_ENDIAN);
1246 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, ENC_BIG_ENDIAN);
1247 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1248 offset = handleDataSegmentAsTextKeys(pinfo, ti, tvb, offset, data_segment_len, end_offset, TRUE);
1249 } else if(opcode == ISCSI_OPCODE_TEXT_RESPONSE) {
1252 gint b = tvb_get_guint8(tvb, offset + 1);
1253 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1254 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1256 proto_tree_add_boolean(tt, hf_iscsi_Text_F, tvb, offset + 1, 1, b);
1257 if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1258 proto_tree_add_boolean(tt, hf_iscsi_Text_C, tvb, offset + 1, 1, b);
1261 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1262 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
1264 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, tvb_get_ntoh24(tvb, offset + 5));
1265 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1266 dissect_scsi_lun(ti, tvb, offset + 8);
1268 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, ENC_BIG_ENDIAN);
1269 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, ENC_BIG_ENDIAN);
1270 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, ENC_BIG_ENDIAN);
1271 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, ENC_BIG_ENDIAN);
1272 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, ENC_BIG_ENDIAN);
1273 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1274 offset = handleDataSegmentAsTextKeys(pinfo, ti, tvb, offset, data_segment_len, end_offset, TRUE);
1275 } else if(opcode == ISCSI_OPCODE_SCSI_DATA_OUT) {
1276 /* SCSI Data Out (write) */
1278 gint b = tvb_get_guint8(tvb, offset + 1);
1279 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1280 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1282 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_F, tvb, offset + 1, 1, b);
1284 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1285 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
1287 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, tvb_get_ntoh24(tvb, offset + 5));
1288 dissect_scsi_lun(ti, tvb, offset + 8);
1289 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, ENC_BIG_ENDIAN);
1290 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, ENC_BIG_ENDIAN);
1291 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, ENC_BIG_ENDIAN);
1292 proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, ENC_BIG_ENDIAN);
1293 proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, ENC_BIG_ENDIAN);
1294 data_offset=tvb_get_ntohl(tvb, offset+40);
1296 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1297 /* do not update offset here because the data segment is
1298 * dissected below */
1299 handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
1300 } else if(opcode == ISCSI_OPCODE_SCSI_DATA_IN) {
1301 /* SCSI Data In (read) */
1303 gint b = tvb_get_guint8(tvb, offset + 1);
1304 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1305 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1307 if(b&ISCSI_SCSI_DATA_FLAG_S){
1311 if(b&ISCSI_SCSI_DATA_FLAG_A){
1314 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_F, tvb, offset + 1, 1, b);
1315 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT08) {
1316 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_A, tvb, offset + 1, 1, b);
1318 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_O, tvb, offset + 1, 1, b);
1319 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_U, tvb, offset + 1, 1, b);
1320 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_S, tvb, offset + 1, 1, b);
1323 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Status, tvb, offset + 3, 1, ENC_BIG_ENDIAN);
1325 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1326 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
1328 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, tvb_get_ntoh24(tvb, offset + 5));
1329 cdata->itlq.data_length=tvb_get_ntoh24(tvb, offset + 5);
1330 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1332 dissect_scsi_lun(ti, tvb, offset + 8);
1335 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, ENC_BIG_ENDIAN);
1336 if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
1337 proto_tree_add_item(ti, hf_iscsi_SCSIData_ResidualCount, tvb, offset + 20, 4, ENC_BIG_ENDIAN);
1341 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, ENC_BIG_ENDIAN);
1344 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, ENC_BIG_ENDIAN);
1345 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, ENC_BIG_ENDIAN);
1346 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, ENC_BIG_ENDIAN);
1347 proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, ENC_BIG_ENDIAN);
1348 proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, ENC_BIG_ENDIAN);
1349 data_offset=tvb_get_ntohl(tvb, offset+40);
1351 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1352 proto_tree_add_item(ti, hf_iscsi_SCSIData_ResidualCount, tvb, offset + 44, 4, ENC_BIG_ENDIAN);
1354 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1355 /* do not update offset here because the data segment is
1356 * dissected below */
1357 handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
1358 } else if(opcode == ISCSI_OPCODE_LOGOUT_COMMAND) {
1359 /* Logout Command */
1360 if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1361 proto_tree_add_item(ti, hf_iscsi_Logout_Reason, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
1363 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1364 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
1365 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, tvb_get_ntoh24(tvb, offset + 5));
1367 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1368 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 8, 2, ENC_BIG_ENDIAN);
1369 proto_tree_add_item(ti, hf_iscsi_Logout_Reason, tvb, offset + 11, 1, ENC_BIG_ENDIAN);
1371 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, ENC_BIG_ENDIAN);
1372 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT08) {
1373 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 20, 2, ENC_BIG_ENDIAN);
1374 if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT13) {
1375 proto_tree_add_item(ti, hf_iscsi_Logout_Reason, tvb, offset + 23, 1, ENC_BIG_ENDIAN);
1378 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, ENC_BIG_ENDIAN);
1379 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, ENC_BIG_ENDIAN);
1380 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1381 } else if(opcode == ISCSI_OPCODE_LOGOUT_RESPONSE) {
1382 /* Logout Response */
1383 proto_tree_add_item(ti, hf_iscsi_Logout_Response, tvb, offset + 2, 1, ENC_BIG_ENDIAN);
1384 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1385 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
1386 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, tvb_get_ntoh24(tvb, offset + 5));
1388 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, ENC_BIG_ENDIAN);
1389 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, ENC_BIG_ENDIAN);
1390 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, ENC_BIG_ENDIAN);
1391 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, ENC_BIG_ENDIAN);
1392 proto_tree_add_item(ti, hf_iscsi_Time2Wait, tvb, offset + 40, 2, ENC_BIG_ENDIAN);
1393 proto_tree_add_item(ti, hf_iscsi_Time2Retain, tvb, offset + 42, 2, ENC_BIG_ENDIAN);
1394 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1395 } else if(opcode == ISCSI_OPCODE_SNACK_REQUEST) {
1399 gint b = tvb_get_guint8(tvb, offset + 1);
1400 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1401 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1404 proto_tree_add_item(ti, hf_iscsi_snack_type, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
1406 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1407 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
1408 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, tvb_get_ntoh24(tvb, offset + 5));
1409 dissect_scsi_lun(ti, tvb, offset + 8);
1411 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, ENC_BIG_ENDIAN);
1412 if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
1413 proto_tree_add_item(ti, hf_iscsi_BegRun, tvb, offset + 20, 4, ENC_BIG_ENDIAN);
1414 proto_tree_add_item(ti, hf_iscsi_RunLength, tvb, offset + 24, 4, ENC_BIG_ENDIAN);
1415 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, ENC_BIG_ENDIAN);
1416 proto_tree_add_item(ti, hf_iscsi_ExpDataSN, tvb, offset + 36, 4, ENC_BIG_ENDIAN);
1419 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, ENC_BIG_ENDIAN);
1420 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, ENC_BIG_ENDIAN);
1421 proto_tree_add_item(ti, hf_iscsi_BegRun, tvb, offset + 40, 4, ENC_BIG_ENDIAN);
1422 proto_tree_add_item(ti, hf_iscsi_RunLength, tvb, offset + 44, 4, ENC_BIG_ENDIAN);
1424 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1425 } else if(opcode == ISCSI_OPCODE_R2T) {
1427 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1428 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
1429 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, tvb_get_ntoh24(tvb, offset + 5));
1430 dissect_scsi_lun(ti, tvb, offset + 8);
1432 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, ENC_BIG_ENDIAN);
1433 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, ENC_BIG_ENDIAN);
1434 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, ENC_BIG_ENDIAN);
1435 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, ENC_BIG_ENDIAN);
1436 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, ENC_BIG_ENDIAN);
1437 proto_tree_add_item(ti, hf_iscsi_R2TSN, tvb, offset + 36, 4, ENC_BIG_ENDIAN);
1438 proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, ENC_BIG_ENDIAN);
1439 proto_tree_add_item(ti, hf_iscsi_DesiredDataLength, tvb, offset + 44, 4, ENC_BIG_ENDIAN);
1440 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1441 } else if(opcode == ISCSI_OPCODE_ASYNC_MESSAGE) {
1444 /* Asynchronous Message */
1445 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1446 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
1448 dsl=tvb_get_ntoh24(tvb, offset+5);
1449 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, tvb_get_ntoh24(tvb, offset + 5));
1450 dissect_scsi_lun(ti, tvb, offset + 8);
1451 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, ENC_BIG_ENDIAN);
1452 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, ENC_BIG_ENDIAN);
1453 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, ENC_BIG_ENDIAN);
1454 proto_tree_add_item(ti, hf_iscsi_AsyncEvent, tvb, offset + 36, 1, ENC_BIG_ENDIAN);
1455 proto_tree_add_item(ti, hf_iscsi_EventVendorCode, tvb, offset + 37, 1, ENC_BIG_ENDIAN);
1456 proto_tree_add_item(ti, hf_iscsi_Parameter1, tvb, offset + 38, 2, ENC_BIG_ENDIAN);
1457 proto_tree_add_item(ti, hf_iscsi_Parameter2, tvb, offset + 40, 2, ENC_BIG_ENDIAN);
1458 proto_tree_add_item(ti, hf_iscsi_Parameter3, tvb, offset + 42, 2, ENC_BIG_ENDIAN);
1459 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1461 /* If we have a datasegment this contains scsi sense info followed
1462 * by iscsi event data. (rfc3720 10.9.4)
1465 snsl=tvb_get_ntohs(tvb, offset);
1469 int tvb_len, tvb_rlen;
1471 tvb_len=tvb_length_remaining(tvb, offset);
1474 tvb_rlen=tvb_reported_length_remaining(tvb, offset);
1477 data_tvb=tvb_new_subset(tvb, offset, tvb_len, tvb_rlen);
1478 dissect_scsi_snsinfo (data_tvb, pinfo, tree, 0,
1484 if((end_offset-offset)>0){
1485 proto_tree_add_item(ti, hf_iscsi_async_event_data, tvb, offset, end_offset-offset, ENC_NA);
1489 } else if(opcode == ISCSI_OPCODE_REJECT) {
1493 const char *next_opcode_str;
1496 proto_tree_add_item(ti, hf_iscsi_Reject_Reason, tvb, offset + 2, 1, ENC_BIG_ENDIAN);
1497 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1498 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
1500 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, tvb_get_ntoh24(tvb, offset + 5));
1501 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, ENC_BIG_ENDIAN);
1502 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, ENC_BIG_ENDIAN);
1503 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, ENC_BIG_ENDIAN);
1504 proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, ENC_BIG_ENDIAN);
1505 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1507 next_opcode = tvb_get_guint8(tvb, offset) & 0x3f;
1508 next_opcode_str = try_val_to_str(next_opcode, iscsi_opcodes);
1510 tf = proto_tree_add_text(ti, tvb, offset, -1, "Rejected Header");
1511 tt = proto_item_add_subtree(tf, ett_iscsi_RejectHeader);
1513 dissect_iscsi_pdu(tvb, pinfo, tt, offset, next_opcode, next_opcode_str, 0, iscsi_session, conversation);
1514 } else if(opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_I0 ||
1515 opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_I1 ||
1516 opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_I2 ||
1517 opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_T0 ||
1518 opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_T1 ||
1519 opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_T2) {
1520 /* Vendor specific opcodes */
1521 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1522 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
1524 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, tvb_get_ntoh24(tvb, offset + 5));
1525 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1526 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_vendor_specific_data);
1531 /* handle request/response matching */
1533 case ISCSI_OPCODE_SCSI_RESPONSE:
1534 if (cdata->itlq.first_exchange_frame){
1535 nstime_t delta_time;
1536 proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->itlq.first_exchange_frame);
1537 nstime_delta(&delta_time, &pinfo->fd->abs_ts, &cdata->itlq.fc_time);
1538 proto_tree_add_time(ti, hf_iscsi_time, tvb, 0, 0, &delta_time);
1540 if (cdata->data_in_frame)
1541 proto_tree_add_uint(ti, hf_iscsi_data_in_frame, tvb, 0, 0, cdata->data_in_frame);
1542 if (cdata->data_out_frame)
1543 proto_tree_add_uint(ti, hf_iscsi_data_out_frame, tvb, 0, 0, cdata->data_out_frame);
1545 case ISCSI_OPCODE_SCSI_DATA_IN:
1546 /* if we have phase collaps then we might have the
1547 response embedded in the last DataIn segment */
1549 if (cdata->itlq.first_exchange_frame)
1550 proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->itlq.first_exchange_frame);
1551 if (cdata->itlq.last_exchange_frame)
1552 proto_tree_add_uint(ti, hf_iscsi_response_frame, tvb, 0, 0, cdata->itlq.last_exchange_frame);
1554 if (cdata->itlq.first_exchange_frame){
1555 nstime_t delta_time;
1556 proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->itlq.first_exchange_frame);
1557 nstime_delta(&delta_time, &pinfo->fd->abs_ts, &cdata->itlq.fc_time);
1558 proto_tree_add_time(ti, hf_iscsi_time, tvb, 0, 0, &delta_time);
1561 if (cdata->data_out_frame)
1562 proto_tree_add_uint(ti, hf_iscsi_data_out_frame, tvb, 0, 0, cdata->data_out_frame);
1564 case ISCSI_OPCODE_SCSI_DATA_OUT:
1565 if (cdata->itlq.first_exchange_frame)
1566 proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->itlq.first_exchange_frame);
1567 if (cdata->data_in_frame)
1568 proto_tree_add_uint(ti, hf_iscsi_data_in_frame, tvb, 0, 0, cdata->data_in_frame);
1569 if (cdata->itlq.last_exchange_frame)
1570 proto_tree_add_uint(ti, hf_iscsi_response_frame, tvb, 0, 0, cdata->itlq.last_exchange_frame);
1572 case ISCSI_OPCODE_SCSI_COMMAND:
1573 if (cdata->data_in_frame)
1574 proto_tree_add_uint(ti, hf_iscsi_data_in_frame, tvb, 0, 0, cdata->data_in_frame);
1575 if (cdata->data_out_frame)
1576 proto_tree_add_uint(ti, hf_iscsi_data_out_frame, tvb, 0, 0, cdata->data_out_frame);
1577 if (cdata->itlq.last_exchange_frame)
1578 proto_tree_add_uint(ti, hf_iscsi_response_frame, tvb, 0, 0, cdata->itlq.last_exchange_frame);
1584 proto_item_set_len(ti, offset - original_offset);
1586 if((opcode & ((iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08)?
1588 ~I_BIT)) == ISCSI_OPCODE_SCSI_COMMAND) {
1589 tvbuff_t *cdb_tvb, *data_tvb;
1590 int tvb_len, tvb_rlen;
1593 tvb_len=tvb_length_remaining(tvb, cdb_offset);
1594 tvb_rlen=tvb_reported_length_remaining(tvb, cdb_offset);
1595 if(ahs_cdb_length && ahs_cdb_length<1024){
1598 /* We have a variable length CDB where bytes >16 is transported
1601 cdb_buf=(guint8 *)wmem_alloc(pinfo->pool, 16+ahs_cdb_length);
1602 /* the 16 first bytes of the cdb */
1603 tvb_memcpy(tvb, cdb_buf, cdb_offset, 16);
1604 /* the remainder of the cdb from the ahs */
1605 tvb_memcpy(tvb, cdb_buf+16, ahs_cdb_offset, ahs_cdb_length);
1607 cdb_tvb = tvb_new_child_real_data(tvb, cdb_buf,
1611 add_new_data_source(pinfo, cdb_tvb, "CDB+AHS");
1619 cdb_tvb=tvb_new_subset(tvb, cdb_offset, tvb_len, tvb_rlen);
1621 dissect_scsi_cdb(cdb_tvb, pinfo, tree, SCSI_DEV_UNKNOWN, &cdata->itlq, itl);
1622 /* we dont want the immediata below to overwrite our CDB info */
1623 col_set_fence(pinfo->cinfo, COL_INFO);
1625 /* where there any ImmediateData ? */
1626 if(immediate_data_length){
1627 /* Immediate Data TVB */
1628 tvb_len=tvb_length_remaining(tvb, immediate_data_offset);
1629 if(tvb_len>(int)immediate_data_length)
1630 tvb_len=immediate_data_length;
1631 tvb_rlen=tvb_reported_length_remaining(tvb, immediate_data_offset);
1632 if(tvb_rlen>(int)immediate_data_length)
1633 tvb_rlen=immediate_data_length;
1634 data_tvb=tvb_new_subset(tvb, immediate_data_offset, tvb_len, tvb_rlen);
1635 dissect_scsi_payload (data_tvb, pinfo, tree,
1641 else if (opcode == ISCSI_OPCODE_SCSI_RESPONSE) {
1642 if (scsi_status == 0x2) {
1643 /* A SCSI response with Check Condition contains sense data */
1644 /* offset is setup correctly by the iscsi code for response above */
1645 if((end_offset - offset) >= 2) {
1646 int senseLen = tvb_get_ntohs(tvb, offset);
1648 proto_tree_add_item(ti, hf_iscsi_SenseLength, tvb, offset, 2, ENC_BIG_ENDIAN);
1652 int tvb_len, tvb_rlen;
1654 tvb_len=tvb_length_remaining(tvb, offset);
1655 if(tvb_len>senseLen)
1657 tvb_rlen=tvb_reported_length_remaining(tvb, offset);
1658 if(tvb_rlen>senseLen)
1660 data_tvb=tvb_new_subset(tvb, offset, tvb_len, tvb_rlen);
1661 dissect_scsi_snsinfo (data_tvb, pinfo, tree, 0,
1668 dissect_scsi_rsp(tvb, pinfo, tree, &cdata->itlq, itl, scsi_status);
1671 else if ((opcode == ISCSI_OPCODE_SCSI_DATA_IN) ||
1672 (opcode == ISCSI_OPCODE_SCSI_DATA_OUT)) {
1674 int tvb_len, tvb_rlen;
1676 /* offset is setup correctly by the iscsi code for response above */
1677 tvb_len=tvb_length_remaining(tvb, offset);
1678 if(tvb_len>(int)data_segment_len)
1679 tvb_len=data_segment_len;
1680 tvb_rlen=tvb_reported_length_remaining(tvb, offset);
1681 if(tvb_rlen>(int)data_segment_len)
1682 tvb_rlen=data_segment_len;
1683 data_tvb=tvb_new_subset(tvb, offset, tvb_len, tvb_rlen);
1684 dissect_scsi_payload (data_tvb, pinfo, tree,
1685 (opcode==ISCSI_OPCODE_SCSI_DATA_OUT),
1691 dissect_scsi_rsp(tvb, pinfo, tree, &cdata->itlq, itl, scsi_status);
1696 dissect_iscsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean check_port) {
1697 /* Set up structures needed to add the protocol subtree and manage it */
1698 guint iSCSIPdusDissected = 0;
1700 guint32 available_bytes = tvb_length(tvb);
1701 int digestsActive = 1;
1702 conversation_t *conversation = NULL;
1703 iscsi_session_t *iscsi_session=NULL;
1704 guint8 opcode, tmpbyte;
1706 if (available_bytes < 48) {
1707 /* heuristic already rejected the packet if size < 48,
1708 assume it's an iscsi packet with a segmented header */
1709 pinfo->desegment_offset = offset;
1710 pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
1714 opcode = tvb_get_guint8(tvb, offset + 0);
1715 opcode &= OPCODE_MASK;
1717 /* heuristics to verify that the packet looks sane. the heuristics
1718 * are based on the RFC version of iscsi.
1719 * (we should retire support for older iscsi versions in wireshark)
1722 /* opcode must be any of the ones from the standard
1723 * also check the header that it looks "sane"
1724 * all reserved or undefined bits in iscsi must be set to zero.
1727 case ISCSI_OPCODE_NOP_IN:
1728 /* top two bits of byte 0 must be 0 */
1729 if(tvb_get_guint8(tvb, offset+0)&0xc0){
1732 /* byte 1 must be 0x80 */
1733 if(tvb_get_guint8(tvb, offset+1)!=0x80){
1736 /* bytes 2 and 3 must be 0 */
1737 if(tvb_get_guint8(tvb, offset+2)||tvb_get_guint8(tvb, offset+3)){
1741 case ISCSI_OPCODE_NOP_OUT:
1742 /* top bit of byte 0 must be 0 */
1743 if(tvb_get_guint8(tvb, offset+0)&0x80){
1746 /* byte 1 must be 0x80 */
1747 if(tvb_get_guint8(tvb, offset+1)!=0x80){
1750 /* bytes 2 and 3 must be 0 */
1751 if(tvb_get_guint8(tvb, offset+2)||tvb_get_guint8(tvb, offset+3)){
1754 /* assume ITT and TTT must always be non NULL (ok they can be NULL
1755 * from time to time but it usually means we are in the middle
1756 * of a zeroed datablock).
1758 if(!tvb_get_letohl(tvb,offset+16) || !tvb_get_letohl(tvb,offset+20)){
1761 /* all reserved bytes between 32 - 47 must be null */
1762 if(tvb_get_letohl(tvb,offset+32)
1763 || tvb_get_letohl(tvb,offset+36)
1764 || tvb_get_letohl(tvb,offset+40)
1765 || tvb_get_letohl(tvb,offset+44)){
1769 case ISCSI_OPCODE_LOGIN_COMMAND:
1770 /* top two bits in byte 0 must be 0x40 */
1771 if((tvb_get_guint8(tvb, offset+0)&0xc0)!=0x40){
1775 /* both the T and C bits can not be set
1776 * and the two reserved bits in byte 1 must be 0
1778 tmpbyte=tvb_get_guint8(tvb, offset+1);
1779 switch(tmpbyte&0xf0){
1787 /* CSG and NSG must not be 2 */
1788 if(((tmpbyte & 0x03) == 0x02)
1789 || ((tmpbyte & 0x0c) == 0x08)) {
1792 /* if T bit is set NSG must not be 0 */
1794 if(!(tmpbyte&0x03)){
1798 /* should we test that datasegmentlen is non zero? */
1800 case ISCSI_OPCODE_LOGIN_RESPONSE:
1801 /* top two bits in byte 0 must be 0 */
1802 if(tvb_get_guint8(tvb, offset+0)&0xc0){
1806 /* both the T and C bits can not be set
1807 * and the two reserved bits in byte 1 must be 0
1809 tmpbyte=tvb_get_guint8(tvb, offset+1);
1810 switch(tmpbyte&0xf0){
1818 /* CSG and NSG must not be 2 */
1819 if(((tmpbyte & 0x03) == 0x02)
1820 || ((tmpbyte & 0x0c) == 0x08)) {
1823 /* if T bit is set NSG must not be 0 */
1825 if(!(tmpbyte&0x03)){
1829 /* the 32bit words at offsets 20, 40, 44 must be zero */
1830 if(tvb_get_letohl(tvb,offset+20)
1831 || tvb_get_letohl(tvb,offset+40)
1832 || tvb_get_letohl(tvb,offset+44)){
1835 /* the two bytes at offset 38 must be zero */
1836 if(tvb_get_letohs(tvb,offset+38)){
1839 /* should we test that datasegmentlen is non zero unless we just
1840 * entered full featured phase?
1843 case ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION:
1844 /* top bit in byte 0 must be 0 */
1845 if(tvb_get_guint8(tvb, offset+0)&0x80){
1848 /* top bit in byte 1 must be set */
1849 tmpbyte=tvb_get_guint8(tvb, offset+1);
1850 if(!(tmpbyte&0x80)){
1853 /* Function must be known */
1854 if(!try_val_to_str(tmpbyte&0x7f, iscsi_task_management_functions)){
1857 /* bytes 2,3 must be null */
1858 if(tvb_get_letohs(tvb,offset+2)){
1861 /* ahs and dsl must be null */
1862 if(tvb_get_letohl(tvb,offset+4)){
1866 case ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE:
1867 /* top two bits in byte 0 must be 0 */
1868 if(tvb_get_guint8(tvb, offset+0)&0xc0){
1871 /* byte 1 must be 0x80 */
1872 if(tvb_get_guint8(tvb, offset+1)!=0x80){
1875 /* response must be 0-6 or 255 */
1876 tmpbyte=tvb_get_guint8(tvb,offset+2);
1877 if(tmpbyte>6 && tmpbyte<255){
1880 /* byte 3 must be 0 */
1881 if(tvb_get_guint8(tvb,offset+3)){
1884 /* ahs and dsl as well as the 32bit words at offsets 8, 12, 20, 36
1885 * 40, 44 must all be 0
1887 if(tvb_get_letohl(tvb,offset+4)
1888 || tvb_get_letohl(tvb,offset+8)
1889 || tvb_get_letohl(tvb,offset+12)
1890 || tvb_get_letohl(tvb,offset+20)
1891 || tvb_get_letohl(tvb,offset+36)
1892 || tvb_get_letohl(tvb,offset+40)
1893 || tvb_get_letohl(tvb,offset+44)){
1897 case ISCSI_OPCODE_LOGOUT_COMMAND:
1898 /* top bit in byte 0 must be 0 */
1899 if(tvb_get_guint8(tvb, offset+0)&0x80){
1902 /* top bit in byte 1 must be set */
1903 tmpbyte=tvb_get_guint8(tvb, offset+1);
1904 if(!(tmpbyte&0x80)){
1907 /* Reason code must be known */
1908 if(!try_val_to_str(tmpbyte&0x7f, iscsi_logout_reasons)){
1911 /* bytes 2,3 must be null */
1912 if(tvb_get_letohs(tvb,offset+2)){
1915 /* ahs and dsl as well as the 32bit words at offsets 8, 12, 32, 36
1916 * 40, 44 must all be 0
1918 if(tvb_get_letohl(tvb,offset+4)
1919 || tvb_get_letohl(tvb,offset+8)
1920 || tvb_get_letohl(tvb,offset+12)
1921 || tvb_get_letohl(tvb,offset+32)
1922 || tvb_get_letohl(tvb,offset+36)
1923 || tvb_get_letohl(tvb,offset+40)
1924 || tvb_get_letohl(tvb,offset+44)){
1928 case ISCSI_OPCODE_SNACK_REQUEST:
1929 /* top two bits in byte 0 must be 0 */
1930 if(tvb_get_guint8(tvb, offset+0)&0xc0){
1933 /* top 4 bits in byte 1 must be 0x80 */
1934 tmpbyte=tvb_get_guint8(tvb, offset+1);
1935 if((tmpbyte&0xf0)!=0x80){
1938 /* type must be known */
1939 if(!try_val_to_str(tmpbyte&0x0f, iscsi_snack_types)){
1942 /* for status/snack and datack itt must be 0xffffffff
1943 * for rdata/snack ttt must not be 0 or 0xffffffff
1945 switch(tmpbyte&0x0f){
1948 if(tvb_get_letohl(tvb,offset+16)!=0xffffffff){
1953 if(tvb_get_letohl(tvb,offset+20)==0xffffffff){
1956 if(tvb_get_letohl(tvb,offset+20)==0){
1961 /* bytes 2,3 must be null */
1962 if(tvb_get_letohs(tvb,offset+2)){
1965 /* the 32bit words at offsets 24, 32, 36
1968 if(tvb_get_letohl(tvb,offset+24)
1969 || tvb_get_letohl(tvb,offset+32)
1970 || tvb_get_letohl(tvb,offset+36)){
1975 case ISCSI_OPCODE_R2T:
1976 /* top two bits in byte 0 must be 0 */
1977 if(tvb_get_guint8(tvb, offset+0)&0xc0){
1980 /* byte 1 must be 0x80 */
1981 if(tvb_get_guint8(tvb, offset+1)!=0x80){
1984 /* bytes 2,3 must be null */
1985 if(tvb_get_letohs(tvb,offset+2)){
1988 /* ahs and dsl must be null */
1989 if(tvb_get_letohl(tvb,offset+4)){
1992 /* desired data transfer length must not be null */
1993 if(!tvb_get_letohl(tvb,offset+44)){
1997 case ISCSI_OPCODE_REJECT:
1998 /* top two bits in byte 0 must be 0 */
1999 if(tvb_get_guint8(tvb, offset+0)&0xc0){
2002 /* byte 1 must be 0x80 */
2003 if(tvb_get_guint8(tvb, offset+1)!=0x80){
2006 /* reason must be known */
2007 if(!try_val_to_str(tvb_get_guint8(tvb,offset+2), iscsi_reject_reasons)){
2010 /* byte 3 must be 0 */
2011 if(tvb_get_guint8(tvb, offset+3)){
2014 /* the 32bit words at offsets 8, 12, 20, 40, 44
2017 if(tvb_get_letohl(tvb,offset+8)
2018 || tvb_get_letohl(tvb,offset+12)
2019 || tvb_get_letohl(tvb,offset+20)
2020 || tvb_get_letohl(tvb,offset+40)
2021 || tvb_get_letohl(tvb,offset+44)){
2024 /* the 32bit word at 16 must be 0xffffffff */
2025 if(tvb_get_letohl(tvb,offset+16)!=0xffffffff){
2029 case ISCSI_OPCODE_TEXT_COMMAND:
2030 /* top bit in byte 0 must be 0 */
2031 if(tvb_get_guint8(tvb, offset+0)&0x80){
2034 /* one of the F and C bits must be set but not both
2035 * low 6 bits in byte 1 must be 0
2037 switch(tvb_get_guint8(tvb,offset+1)){
2044 /* bytes 2,3 must be null */
2045 if(tvb_get_letohs(tvb,offset+2)){
2048 /* the 32bit words at offsets 32, 36, 40, 44
2051 if(tvb_get_letohl(tvb,offset+32)
2052 || tvb_get_letohl(tvb,offset+36)
2053 || tvb_get_letohl(tvb,offset+40)
2054 || tvb_get_letohl(tvb,offset+44)){
2058 case ISCSI_OPCODE_TEXT_RESPONSE:
2059 /* top two bits in byte 0 must be 0 */
2060 if(tvb_get_guint8(tvb, offset+0)&0xc0){
2063 /* one of the F and C bits must be set but not both
2064 * low 6 bits in byte 1 must be 0
2066 switch(tvb_get_guint8(tvb,offset+1)){
2073 /* bytes 2,3 must be null */
2074 if(tvb_get_letohs(tvb,offset+2)){
2077 /* the 32bit words at offsets 36, 40, 44
2080 if(tvb_get_letohl(tvb,offset+36)
2081 || tvb_get_letohl(tvb,offset+40)
2082 || tvb_get_letohl(tvb,offset+44)){
2086 case ISCSI_OPCODE_SCSI_COMMAND:
2087 /* top bit in byte 0 must be 0 */
2088 if(tvb_get_guint8(tvb, offset+0)&0x80){
2091 /* reserved bits in byte 1 must be 0 */
2092 if(tvb_get_guint8(tvb, offset+1)&0x18){
2095 /* bytes 2,3 must be null */
2096 if(tvb_get_letohs(tvb,offset+2)){
2099 /* last 6 bytes of LUN are always 0 */
2100 if(tvb_get_ntoh48(tvb, offset+10)){
2103 /* expected data transfer length is never >16MByte ? */
2104 if(tvb_get_guint8(tvb,offset+20)){
2108 case ISCSI_OPCODE_SCSI_RESPONSE:
2109 /* top two bits in byte 0 must be 0 */
2110 if(tvb_get_guint8(tvb, offset+0)&0xc0){
2113 /* top bit in byte 1 must be 1 */
2114 tmpbyte=tvb_get_guint8(tvb,offset+1);
2115 if(!(tmpbyte&0x80)){
2118 /* the reserved bits in byte 1 must be 0 */
2122 /* status must be known */
2123 if(!try_val_to_str(tvb_get_guint8(tvb,offset+3), scsi_status_val)){
2126 /* the 32bit words at offsets 8, 12
2129 if(tvb_get_letohl(tvb,offset+8)
2130 || tvb_get_letohl(tvb,offset+12)){
2134 case ISCSI_OPCODE_ASYNC_MESSAGE:
2135 /* top two bits in byte 0 must be 0 */
2136 if(tvb_get_guint8(tvb, offset+0)&0xc0){
2139 /* byte 1 must be 0x80 */
2140 if(tvb_get_guint8(tvb, offset+1)!=0x80){
2143 /* bytes 2,3 must be null */
2144 if(tvb_get_letohs(tvb,offset+2)){
2147 /* the 32bit words at offsets 20, 44
2150 if(tvb_get_letohl(tvb,offset+20)
2151 || tvb_get_letohl(tvb,offset+44)){
2154 /* the 32bit word at 16 must be 0xffffffff */
2155 if(tvb_get_letohl(tvb,offset+16)!=0xffffffff){
2159 case ISCSI_OPCODE_LOGOUT_RESPONSE:
2160 /* top two bits in byte 0 must be 0 */
2161 if(tvb_get_guint8(tvb, offset+0)&0xc0){
2164 /* byte 1 must be 0x80 */
2165 if(tvb_get_guint8(tvb, offset+1)!=0x80){
2168 /* response must be known */
2169 if(!try_val_to_str(tvb_get_guint8(tvb,offset+2), iscsi_logout_response)){
2172 /* byte 3 must be 0 */
2173 if(tvb_get_guint8(tvb,offset+3)){
2176 /* ahs and dsl as well as the 32bit words at offsets 8, 12, 20, 36
2179 if(tvb_get_letohl(tvb,offset+4)
2180 || tvb_get_letohl(tvb,offset+8)
2181 || tvb_get_letohl(tvb,offset+12)
2182 || tvb_get_letohl(tvb,offset+20)
2183 || tvb_get_letohl(tvb,offset+36)
2184 || tvb_get_letohl(tvb,offset+44)){
2188 case ISCSI_OPCODE_SCSI_DATA_OUT:
2189 /* top two bits in byte 0 must be 0 */
2190 if(tvb_get_guint8(tvb, offset+0)&0xc0){
2193 /* low 7 bits in byte 1 must be 0 */
2194 if(tvb_get_guint8(tvb,offset+1)&0x7f){
2197 /* bytes 2,3 must be null */
2198 if(tvb_get_letohs(tvb,offset+2)){
2201 /* the 32bit words at offsets 24, 32, 44
2204 if(tvb_get_letohl(tvb,offset+24)
2205 || tvb_get_letohl(tvb,offset+32)
2206 || tvb_get_letohl(tvb,offset+44)){
2210 case ISCSI_OPCODE_SCSI_DATA_IN:
2211 /* top two bits in byte 0 must be 0 */
2212 if(tvb_get_guint8(tvb, offset+0)&0xc0){
2215 /* reserved bits in byte 1 must be 0 */
2216 if(tvb_get_guint8(tvb,offset+1)&0x38){
2219 /* byte 2 must be reserved */
2220 if(tvb_get_guint8(tvb,offset+2)){
2224 case ISCSI_OPCODE_VENDOR_SPECIFIC_I0:
2225 case ISCSI_OPCODE_VENDOR_SPECIFIC_I1:
2226 case ISCSI_OPCODE_VENDOR_SPECIFIC_I2:
2227 case ISCSI_OPCODE_VENDOR_SPECIFIC_T0:
2228 case ISCSI_OPCODE_VENDOR_SPECIFIC_T1:
2229 case ISCSI_OPCODE_VENDOR_SPECIFIC_T2:
2236 /* process multiple iSCSI PDUs per packet */
2237 while(available_bytes >= 48 || (iscsi_desegment && available_bytes >= 8)) {
2238 const char *opcode_str = NULL;
2239 guint32 data_segment_len;
2240 guint32 pduLen = 48;
2241 guint8 secondPduByte = tvb_get_guint8(tvb, offset + 1);
2245 /* mask out any extra bits in the opcode byte */
2246 opcode = tvb_get_guint8(tvb, offset + 0);
2247 opcode &= OPCODE_MASK;
2249 opcode_str = try_val_to_str(opcode, iscsi_opcodes);
2250 if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION ||
2251 opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE ||
2252 opcode == ISCSI_OPCODE_R2T ||
2253 opcode == ISCSI_OPCODE_LOGOUT_COMMAND ||
2254 opcode == ISCSI_OPCODE_LOGOUT_RESPONSE ||
2255 opcode == ISCSI_OPCODE_SNACK_REQUEST)
2256 data_segment_len = 0;
2258 data_segment_len = tvb_get_ntohl(tvb, offset + 4) & 0x00ffffff;
2260 if(opcode_str == NULL) {
2265 if(!badPdu && check_port) {
2267 if ((opcode & TARGET_OPCODE_BIT) && value_is_in_range(global_iscsi_port_range, pinfo->srcport)) {
2270 if (!(opcode & TARGET_OPCODE_BIT) && value_is_in_range(global_iscsi_port_range, pinfo->destport)) {
2273 if ((opcode & TARGET_OPCODE_BIT) && pinfo->srcport == iscsi_system_port) {
2276 if (!(opcode & TARGET_OPCODE_BIT) && pinfo->destport == iscsi_system_port) {
2281 if(!badPdu && enable_bogosity_filter) {
2282 /* try and distinguish between data and real headers */
2283 if(data_segment_len > bogus_pdu_data_length_threshold) {
2286 else if(demand_good_f_bit &&
2287 !(secondPduByte & 0x80) &&
2288 (opcode == ISCSI_OPCODE_NOP_OUT ||
2289 opcode == ISCSI_OPCODE_NOP_IN ||
2290 opcode == ISCSI_OPCODE_LOGOUT_COMMAND ||
2291 opcode == ISCSI_OPCODE_LOGOUT_RESPONSE ||
2292 opcode == ISCSI_OPCODE_SCSI_RESPONSE ||
2293 opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE ||
2294 opcode == ISCSI_OPCODE_R2T ||
2295 opcode == ISCSI_OPCODE_ASYNC_MESSAGE ||
2296 opcode == ISCSI_OPCODE_SNACK_REQUEST ||
2297 opcode == ISCSI_OPCODE_REJECT)) {
2299 } else if(opcode==ISCSI_OPCODE_NOP_OUT) {
2300 /* TransferTag for NOP-Out should either be -1 or
2301 the tag value we want for a response.
2302 Assume 0 means we are just inside a big all zero
2305 if(tvb_get_ntohl(tvb, offset+20)==0){
2312 return iSCSIPdusDissected > 0;
2315 if(opcode == ISCSI_OPCODE_LOGIN_COMMAND ||
2316 opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
2317 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
2318 if((secondPduByte & CSG_MASK) < ISCSI_CSG_OPERATIONAL_NEGOTIATION) {
2319 /* digests are not yet turned on */
2327 if(opcode == ISCSI_OPCODE_SCSI_COMMAND) {
2329 ahsLen = tvb_get_guint8(tvb, offset + 4);
2330 pduLen += ahsLen * 4;
2333 pduLen += data_segment_len;
2334 if((pduLen & 3) != 0)
2335 pduLen += 4 - (pduLen & 3);
2338 if(digestsActive && data_segment_len > 0 && enableDataDigests) {
2339 if(dataDigestIsCRC32)
2342 pduLen += dataDigestSize;
2345 /* make sure we have a conversation for this session */
2346 conversation = find_or_create_conversation(pinfo);
2348 iscsi_session=(iscsi_session_t *)conversation_get_proto_data(conversation, proto_iscsi);
2350 iscsi_session = wmem_new(wmem_file_scope(), iscsi_session_t);
2351 iscsi_session->header_digest = ISCSI_HEADER_DIGEST_AUTO;
2352 iscsi_session->itlq = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
2353 iscsi_session->itl = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
2354 conversation_add_proto_data(conversation, proto_iscsi, iscsi_session);
2356 /* DataOut PDUs are often mistaken by DCERPC heuristics to be
2357 * that protocol. Now that we know this is iscsi, set a
2358 * dissector for this conversation to block other heuristic
2361 conversation_set_dissector(conversation, iscsi_handle);
2363 /* try to autodetect if header digest is used or not */
2364 if(digestsActive && (available_bytes>=(guint32) (48+4+ahsLen*4)) && (iscsi_session->header_digest==ISCSI_HEADER_DIGEST_AUTO) ){
2366 /* we have enough data to test if HeaderDigest is enabled */
2367 crc= ~crc32c_calculate(tvb_get_ptr(tvb, offset, 48+ahsLen*4), 48+ahsLen*4, CRC32C_PRELOAD);
2368 if(crc==tvb_get_ntohl(tvb,48+ahsLen*4)){
2369 iscsi_session->header_digest=ISCSI_HEADER_DIGEST_CRC32;
2371 iscsi_session->header_digest=ISCSI_HEADER_DIGEST_NONE;
2376 /* Add header digest length to pdulen */
2378 switch(iscsi_session->header_digest){
2379 case ISCSI_HEADER_DIGEST_CRC32:
2382 case ISCSI_HEADER_DIGEST_NONE:
2384 case ISCSI_HEADER_DIGEST_AUTO:
2385 /* oops we didnt know what digest is used yet */
2386 /* here we should use some default */
2389 DISSECTOR_ASSERT_NOT_REACHED();
2394 * Desegmentation check.
2396 if(iscsi_desegment && pinfo->can_desegment) {
2397 if(pduLen > available_bytes) {
2399 * This frame doesn't have all of the data for
2400 * this message, but we can do reassembly on it.
2402 * Tell the TCP dissector where the data for this
2403 * message starts in the data it handed us, and
2404 * how many more bytes we need, and return.
2406 pinfo->desegment_offset = offset;
2407 pinfo->desegment_len = pduLen - available_bytes;
2412 /* This is to help TCP keep track of PDU boundaries
2413 and allows it to find PDUs that are not aligned to
2414 the start of a TCP segments.
2415 Since it also allows TCP to know what is in the middle
2416 of a large PDU, it reduces the probability of a segment
2417 in the middle of a large PDU transfer being misdissected as
2420 if(!pinfo->fd->flags.visited){
2421 if(pduLen>(guint32)tvb_reported_length_remaining(tvb, offset)){
2422 pinfo->want_pdu_tracking=2;
2423 pinfo->bytes_until_next_pdu=pduLen-tvb_reported_length_remaining(tvb, offset);
2427 if(iSCSIPdusDissected == 0)
2428 col_set_str(pinfo->cinfo, COL_INFO, "");
2430 col_append_str(pinfo->cinfo, COL_INFO, ", ");
2432 dissect_iscsi_pdu(tvb, pinfo, tree, offset, opcode, opcode_str, data_segment_len, iscsi_session, conversation);
2433 if(pduLen > available_bytes)
2434 pduLen = available_bytes;
2436 available_bytes -= pduLen;
2437 ++iSCSIPdusDissected;
2440 return iSCSIPdusDissected > 0;
2443 /* This is called for those sessions where we have explicitly said
2444 this to be iSCSI using "Decode As..."
2445 In this case we will not check the port number for sanity and just
2446 do as the user said.
2447 We still check that the PDU header looks sane though.
2450 dissect_iscsi_handle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
2451 return dissect_iscsi(tvb, pinfo, tree, FALSE);
2454 /* This is called through the heuristic handler.
2455 In this case we also want to check that the port matches the preference
2456 setting for iSCSI in order to reduce the number of
2460 dissect_iscsi_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
2461 guint32 available_bytes = tvb_length(tvb);
2463 /* quick check to see if the packet is long enough to contain the
2464 * minimum amount of information we need */
2465 if (available_bytes < 48 ){
2466 /* no, so give up */
2470 return dissect_iscsi(tvb, pinfo, tree, TRUE);
2474 /* Register the protocol with Wireshark */
2477 * this format is require because a script is used to build the C
2478 * function that calls all the protocol registration.
2482 proto_register_iscsi(void)
2484 module_t *iscsi_module;
2486 /* Setup list of header fields See Section 1.6.1 for details*/
2487 static hf_register_info hf[] = {
2488 { &hf_iscsi_request_frame,
2489 { "Request in", "iscsi.request_frame",
2490 FT_FRAMENUM, BASE_NONE, NULL, 0,
2491 "The request to this transaction is in this frame", HFILL }},
2494 { "Time from request", "iscsi.time",
2495 FT_RELATIVE_TIME, BASE_NONE, NULL, 0,
2496 "Time between the Command and the Response", HFILL }},
2498 { &hf_iscsi_data_in_frame,
2499 { "Data In in", "iscsi.data_in_frame",
2500 FT_FRAMENUM, BASE_NONE, NULL, 0,
2501 "The Data In for this transaction is in this frame", HFILL }},
2503 { &hf_iscsi_data_out_frame,
2504 { "Data Out in", "iscsi.data_out_frame",
2505 FT_FRAMENUM, BASE_NONE, NULL, 0,
2506 "The Data Out for this transaction is in this frame", HFILL }},
2508 { &hf_iscsi_response_frame,
2509 { "Response in", "iscsi.response_frame",
2510 FT_FRAMENUM, BASE_NONE, NULL, 0,
2511 "The response to this transaction is in this frame", HFILL }},
2512 { &hf_iscsi_AHS_length,
2513 { "AHS Length", "iscsi.ahs.length",
2514 FT_UINT16, BASE_DEC, NULL, 0,
2515 "Length of Additional header segment", HFILL }
2517 { &hf_iscsi_AHS_read_data_length,
2518 { "Bidirectional Read Data Length", "iscsi.ahs.bidir.length",
2519 FT_UINT32, BASE_DEC, NULL, 0,
2522 { &hf_iscsi_AHS_type,
2523 { "AHS Type", "iscsi.ahs.type",
2524 FT_UINT8, BASE_DEC, VALS(ahs_type_vals), 0,
2525 "Type of Additional header segment", HFILL }
2527 { &hf_iscsi_AHS_extended_cdb,
2528 { "AHS Extended CDB", "iscsi.ahs.extended_cdb",
2529 FT_BYTES, BASE_NONE, NULL, 0,
2532 { &hf_iscsi_AHS_blob,
2533 { "Unknown AHS blob", "iscsi.ahs.unknown_blob",
2534 FT_BYTES, BASE_NONE, NULL, 0,
2537 { &hf_iscsi_Padding,
2538 { "Padding", "iscsi.padding",
2539 FT_BYTES, BASE_NONE, NULL, 0,
2540 "Padding to 4 byte boundary", HFILL }
2542 { &hf_iscsi_ping_data,
2543 { "PingData", "iscsi.pingdata",
2544 FT_BYTES, BASE_NONE, NULL, 0,
2545 "Ping Data", HFILL }
2547 { &hf_iscsi_immediate_data,
2548 { "ImmediateData", "iscsi.immediatedata",
2549 FT_BYTES, BASE_NONE, NULL, 0,
2550 "Immediate Data", HFILL }
2552 { &hf_iscsi_async_event_data,
2553 { "AsyncEventData", "iscsi.asynceventdata",
2554 FT_BYTES, BASE_NONE, NULL, 0,
2555 "Async Event Data", HFILL }
2557 { &hf_iscsi_vendor_specific_data,
2558 { "VendorSpecificData", "iscsi.vendorspecificdata",
2559 FT_BYTES, BASE_NONE, NULL, 0,
2560 "Vendor Specific Data", HFILL }
2562 { &hf_iscsi_HeaderDigest32,
2563 { "HeaderDigest", "iscsi.headerdigest32",
2564 FT_UINT32, BASE_HEX, NULL, 0,
2565 "Header Digest", HFILL }
2567 { &hf_iscsi_DataDigest,
2568 { "DataDigest", "iscsi.datadigest",
2569 FT_BYTES, BASE_NONE, NULL, 0,
2570 "Data Digest", HFILL }
2572 { &hf_iscsi_DataDigest32,
2573 { "DataDigest", "iscsi.datadigest32",
2574 FT_UINT32, BASE_HEX, NULL, 0,
2575 "Data Digest", HFILL }
2578 { "Opcode", "iscsi.opcode",
2579 FT_UINT8, BASE_HEX, VALS(iscsi_opcodes), 0,
2582 /* #ifdef DRAFT08 */
2585 FT_BOOLEAN, 8, TFS(&iscsi_meaning_X), 0x80,
2586 "Command Retry", HFILL }
2591 FT_BOOLEAN, 8, TFS(&iscsi_meaning_I), 0x40,
2592 "Immediate delivery", HFILL }
2595 { "Flags", "iscsi.flags",
2596 FT_UINT8, BASE_HEX, NULL, 0,
2597 "Opcode specific flags", HFILL }
2599 { &hf_iscsi_SCSICommand_F,
2600 { "F", "iscsi.scsicommand.F",
2601 FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,
2602 "PDU completes command", HFILL }
2604 { &hf_iscsi_SCSICommand_R,
2605 { "R", "iscsi.scsicommand.R",
2606 FT_BOOLEAN, 8, TFS(&iscsi_meaning_R), 0x40,
2607 "Command reads from SCSI target", HFILL }
2609 { &hf_iscsi_SCSICommand_W,
2610 { "W", "iscsi.scsicommand.W",
2611 FT_BOOLEAN, 8, TFS(&iscsi_meaning_W), 0x20,
2612 "Command writes to SCSI target", HFILL }
2614 { &hf_iscsi_SCSICommand_Attr,
2615 { "Attr", "iscsi.scsicommand.attr",
2616 FT_UINT8, BASE_HEX, VALS(iscsi_scsicommand_taskattrs), 0x07,
2617 "SCSI task attributes", HFILL }
2619 { &hf_iscsi_SCSICommand_CRN,
2620 { "CRN", "iscsi.scsicommand.crn",
2621 FT_UINT8, BASE_HEX, NULL, 0,
2622 "SCSI command reference number", HFILL }
2624 { &hf_iscsi_DataSegmentLength,
2625 { "DataSegmentLength", "iscsi.datasegmentlength",
2626 FT_UINT32, BASE_DEC_HEX, NULL, 0,
2627 "Data segment length (bytes)", HFILL }
2629 { &hf_iscsi_TotalAHSLength,
2630 { "TotalAHSLength", "iscsi.totalahslength",
2631 FT_UINT8, BASE_HEX, NULL, 0,
2632 "Total additional header segment length (4 byte words)", HFILL }
2634 { &hf_iscsi_InitiatorTaskTag,
2635 { "InitiatorTaskTag", "iscsi.initiatortasktag",
2636 FT_UINT32, BASE_HEX, NULL, 0,
2637 "Initiator's task tag", HFILL }
2639 { &hf_iscsi_ExpectedDataTransferLength,
2640 { "ExpectedDataTransferLength", "iscsi.scsicommand.expecteddatatransferlength",
2641 FT_UINT32, BASE_HEX, NULL, 0,
2642 "Expected length of data transfer", HFILL }
2645 { "CmdSN", "iscsi.cmdsn",
2646 FT_UINT32, BASE_HEX, NULL, 0,
2647 "Sequence number for this command", HFILL }
2649 { &hf_iscsi_ExpStatSN,
2650 { "ExpStatSN", "iscsi.expstatsn",
2651 FT_UINT32, BASE_HEX, NULL, 0,
2652 "Next expected status sequence number", HFILL }
2654 { &hf_iscsi_SCSIResponse_ResidualCount,
2655 { "ResidualCount", "iscsi.scsiresponse.residualcount",
2656 FT_UINT32, BASE_HEX, NULL, 0,
2657 "Residual count", HFILL }
2660 { "StatSN", "iscsi.statsn",
2661 FT_UINT32, BASE_HEX, NULL, 0,
2662 "Status sequence number", HFILL }
2664 { &hf_iscsi_ExpCmdSN,
2665 { "ExpCmdSN", "iscsi.expcmdsn",
2666 FT_UINT32, BASE_HEX, NULL, 0,
2667 "Next expected command sequence number", HFILL }
2669 { &hf_iscsi_MaxCmdSN,
2670 { "MaxCmdSN", "iscsi.maxcmdsn",
2671 FT_UINT32, BASE_HEX, NULL, 0,
2672 "Maximum acceptable command sequence number", HFILL }
2674 { &hf_iscsi_SCSIResponse_o,
2675 { "o", "iscsi.scsiresponse.o",
2676 FT_BOOLEAN, 8, TFS(&iscsi_meaning_o), 0x10,
2677 "Bi-directional read residual overflow", HFILL }
2679 { &hf_iscsi_SCSIResponse_u,
2680 { "u", "iscsi.scsiresponse.u",
2681 FT_BOOLEAN, 8, TFS(&iscsi_meaning_u), 0x08,
2682 "Bi-directional read residual underflow", HFILL }
2684 { &hf_iscsi_SCSIResponse_O,
2685 { "O", "iscsi.scsiresponse.O",
2686 FT_BOOLEAN, 8, TFS(&iscsi_meaning_O), 0x04,
2687 "Residual overflow", HFILL }
2689 { &hf_iscsi_SCSIResponse_U,
2690 { "U", "iscsi.scsiresponse.U",
2691 FT_BOOLEAN, 8, TFS(&iscsi_meaning_U), 0x02,
2692 "Residual underflow", HFILL }
2694 { &hf_iscsi_SCSIResponse_Status,
2695 { "Status", "iscsi.scsiresponse.status",
2696 FT_UINT8, BASE_HEX, VALS(scsi_status_val), 0,
2697 "SCSI command status value", HFILL }
2699 { &hf_iscsi_SCSIResponse_Response,
2700 { "Response", "iscsi.scsiresponse.response",
2701 FT_UINT8, BASE_HEX, VALS(iscsi_scsi_responses), 0,
2702 "SCSI command response value", HFILL }
2704 { &hf_iscsi_SCSIResponse_BidiReadResidualCount,
2705 { "BidiReadResidualCount", "iscsi.scsiresponse.bidireadresidualcount",
2706 FT_UINT32, BASE_HEX, NULL, 0,
2707 "Bi-directional read residual count", HFILL }
2709 { &hf_iscsi_SenseLength,
2710 { "SenseLength", "iscsi.scsiresponse.senselength",
2711 FT_UINT16, BASE_HEX, NULL, 0,
2712 "Sense data length", HFILL }
2714 { &hf_iscsi_SCSIData_F,
2715 { "F", "iscsi.scsidata.F",
2716 FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), ISCSI_SCSI_DATA_FLAG_F,
2717 "Final PDU", HFILL }
2719 { &hf_iscsi_SCSIData_A,
2720 { "A", "iscsi.scsidata.A",
2721 FT_BOOLEAN, 8, TFS(&iscsi_meaning_A), ISCSI_SCSI_DATA_FLAG_A,
2722 "Acknowledge Requested", HFILL }
2724 { &hf_iscsi_SCSIData_S,
2725 { "S", "iscsi.scsidata.S",
2726 FT_BOOLEAN, 8, TFS(&iscsi_meaning_S), ISCSI_SCSI_DATA_FLAG_S,
2727 "PDU Contains SCSI command status", HFILL }
2729 { &hf_iscsi_SCSIData_U,
2730 { "U", "iscsi.scsidata.U",
2731 FT_BOOLEAN, 8, TFS(&iscsi_meaning_U), ISCSI_SCSI_DATA_FLAG_U,
2732 "Residual underflow", HFILL }
2734 { &hf_iscsi_SCSIData_O,
2735 { "O", "iscsi.scsidata.O",
2736 FT_BOOLEAN, 8, TFS(&iscsi_meaning_O), ISCSI_SCSI_DATA_FLAG_O,
2737 "Residual overflow", HFILL }
2739 { &hf_iscsi_TargetTransferTag,
2740 { "TargetTransferTag", "iscsi.targettransfertag",
2741 FT_UINT32, BASE_HEX, NULL, 0,
2742 "Target transfer tag", HFILL }
2744 { &hf_iscsi_BufferOffset,
2745 { "BufferOffset", "iscsi.bufferOffset",
2746 FT_UINT32, BASE_HEX, NULL, 0,
2747 "Buffer offset", HFILL }
2749 { &hf_iscsi_SCSIData_ResidualCount,
2750 { "ResidualCount", "iscsi.scsidata.readresidualcount",
2751 FT_UINT32, BASE_HEX, NULL, 0,
2752 "Residual count", HFILL }
2755 { "DataSN", "iscsi.datasn",
2756 FT_UINT32, BASE_HEX, NULL, 0,
2757 "Data sequence number", HFILL }
2759 { &hf_iscsi_VersionMax,
2760 { "VersionMax", "iscsi.versionmax",
2761 FT_UINT8, BASE_HEX, NULL, 0,
2762 "Maximum supported protocol version", HFILL }
2764 { &hf_iscsi_VersionMin,
2765 { "VersionMin", "iscsi.versionmin",
2766 FT_UINT8, BASE_HEX, NULL, 0,
2767 "Minimum supported protocol version", HFILL }
2769 { &hf_iscsi_VersionActive,
2770 { "VersionActive", "iscsi.versionactive",
2771 FT_UINT8, BASE_HEX, NULL, 0,
2772 "Negotiated protocol version", HFILL }
2775 { "CID", "iscsi.cid",
2776 FT_UINT16, BASE_HEX, NULL, 0,
2777 "Connection identifier", HFILL }
2779 /* #ifdef DRAFT08 */
2781 { "ISID", "iscsi.isid",
2782 FT_UINT16, BASE_HEX, NULL, 0,
2783 "Initiator part of session identifier", HFILL }
2787 { "ISID", "iscsi.isid",
2788 FT_BYTES, BASE_NONE, NULL, 0,
2789 "Initiator part of session identifier", HFILL }
2791 /* #ifdef DRAFT09 */
2792 { &hf_iscsi_ISID_Type,
2793 { "ISID_Type", "iscsi.isid.type",
2794 FT_UINT8, BASE_HEX, VALS(iscsi_isid_type), 0,
2795 "Initiator part of session identifier - type", HFILL }
2797 { &hf_iscsi_ISID_NamingAuthority,
2798 { "ISID_NamingAuthority", "iscsi.isid.namingauthority",
2799 FT_UINT24, BASE_HEX, NULL, 0,
2800 "Initiator part of session identifier - naming authority", HFILL }
2802 { &hf_iscsi_ISID_Qualifier,
2803 { "ISID_Qualifier", "iscsi.isid.qualifier",
2804 FT_UINT8, BASE_HEX, NULL, 0,
2805 "Initiator part of session identifier - qualifier", HFILL }
2809 { "ISID_t", "iscsi.isid.t",
2810 FT_UINT8, BASE_HEX, VALS(iscsi_isid_type), 0xc0,
2811 "Initiator part of session identifier - t", HFILL }
2814 { "ISID_a", "iscsi.isid.a",
2815 FT_UINT8, BASE_HEX, NULL, 0x3f,
2816 "Initiator part of session identifier - a", HFILL }
2819 { "ISID_b", "iscsi.isid.b",
2820 FT_UINT16, BASE_HEX, NULL, 0,
2821 "Initiator part of session identifier - b", HFILL }
2824 { "ISID_c", "iscsi.isid.c",
2825 FT_UINT8, BASE_HEX, NULL, 0,
2826 "Initiator part of session identifier - c", HFILL }
2829 { "ISID_d", "iscsi.isid.d",
2830 FT_UINT16, BASE_HEX, NULL, 0,
2831 "Initiator part of session identifier - d", HFILL }
2836 { "TSID", "iscsi.tsid",
2837 FT_UINT16, BASE_HEX, NULL, 0,
2838 "Target part of session identifier", HFILL }
2841 { "TSIH", "iscsi.tsih",
2842 FT_UINT16, BASE_HEX, NULL, 0,
2843 "Target session identifying handle", HFILL }
2845 { &hf_iscsi_Login_T,
2846 { "T", "iscsi.login.T",
2847 FT_BOOLEAN, 8, TFS(&iscsi_meaning_T), 0x80,
2848 "Transit to next login stage", HFILL }
2850 { &hf_iscsi_Login_C,
2851 { "C", "iscsi.login.C",
2852 FT_BOOLEAN, 8, TFS(&iscsi_meaning_C), 0x40,
2853 "Text incomplete", HFILL }
2855 /* #ifdef DRAFT09 */
2856 { &hf_iscsi_Login_X,
2857 { "X", "iscsi.login.X",
2858 FT_BOOLEAN, 8, TFS(&iscsi_meaning_login_X), 0x40,
2859 "Restart Connection", HFILL }
2862 { &hf_iscsi_Login_CSG,
2863 { "CSG", "iscsi.login.csg",
2864 FT_UINT8, BASE_HEX, VALS(iscsi_login_stage), CSG_MASK,
2865 "Current stage", HFILL }
2867 { &hf_iscsi_Login_NSG,
2868 { "NSG", "iscsi.login.nsg",
2869 FT_UINT8, BASE_HEX, VALS(iscsi_login_stage), NSG_MASK,
2870 "Next stage", HFILL }
2872 { &hf_iscsi_Login_Status,
2873 { "Status", "iscsi.login.status",
2874 FT_UINT16, BASE_HEX, VALS(iscsi_login_status), 0,
2875 "Status class and detail", HFILL }
2877 { &hf_iscsi_KeyValue,
2878 { "KeyValue", "iscsi.keyvalue",
2879 FT_STRING, BASE_NONE, NULL, 0,
2880 "Key/value pair", HFILL }
2883 { "F", "iscsi.text.F",
2884 FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,
2885 "Final PDU in text sequence", HFILL }
2888 { "C", "iscsi.text.C",
2889 FT_BOOLEAN, 8, TFS(&iscsi_meaning_C), 0x40,
2890 "Text incomplete", HFILL }
2892 { &hf_iscsi_ExpDataSN,
2893 { "ExpDataSN", "iscsi.expdatasn",
2894 FT_UINT32, BASE_HEX, NULL, 0,
2895 "Next expected data sequence number", HFILL }
2898 { "R2TSN", "iscsi.r2tsn",
2899 FT_UINT32, BASE_HEX, NULL, 0,
2900 "R2T PDU Number", HFILL }
2902 { &hf_iscsi_TaskManagementFunction_Response,
2903 { "Response", "iscsi.taskmanfun.response",
2904 FT_UINT8, BASE_HEX, VALS(iscsi_task_management_responses), 0,
2907 { &hf_iscsi_TaskManagementFunction_ReferencedTaskTag,
2908 { "ReferencedTaskTag", "iscsi.taskmanfun.referencedtasktag",
2909 FT_UINT32, BASE_HEX, NULL, 0,
2910 "Referenced task tag", HFILL }
2912 { &hf_iscsi_RefCmdSN,
2913 { "RefCmdSN", "iscsi.refcmdsn",
2914 FT_UINT32, BASE_HEX, NULL, 0,
2915 "Command sequence number for command to be aborted", HFILL }
2917 { &hf_iscsi_TaskManagementFunction_Function,
2918 { "Function", "iscsi.taskmanfun.function",
2919 FT_UINT8, BASE_HEX, VALS(iscsi_task_management_functions), 0x7F,
2920 "Requested task function", HFILL }
2922 { &hf_iscsi_Logout_Reason,
2923 { "Reason", "iscsi.logout.reason",
2924 FT_UINT8, BASE_HEX, VALS(iscsi_logout_reasons), 0x7F,
2925 "Reason for logout", HFILL }
2927 { &hf_iscsi_Logout_Response,
2928 { "Response", "iscsi.logout.response",
2929 FT_UINT8, BASE_HEX, VALS(iscsi_logout_response), 0,
2930 "Logout response", HFILL }
2932 { &hf_iscsi_Time2Wait,
2933 { "Time2Wait", "iscsi.time2wait",
2934 FT_UINT16, BASE_HEX, NULL, 0,
2937 { &hf_iscsi_Time2Retain,
2938 { "Time2Retain", "iscsi.time2retain",
2939 FT_UINT16, BASE_HEX, NULL, 0,
2942 { &hf_iscsi_DesiredDataLength,
2943 { "DesiredDataLength", "iscsi.desireddatalength",
2944 FT_UINT32, BASE_HEX, NULL, 0,
2945 "Desired data length (bytes)", HFILL }
2947 { &hf_iscsi_AsyncEvent,
2948 { "AsyncEvent", "iscsi.asyncevent",
2949 FT_UINT8, BASE_HEX, VALS(iscsi_asyncevents), 0,
2950 "Async event type", HFILL }
2952 { &hf_iscsi_EventVendorCode,
2953 { "EventVendorCode", "iscsi.eventvendorcode",
2954 FT_UINT8, BASE_HEX, NULL, 0,
2955 "Event vendor code", HFILL }
2957 { &hf_iscsi_Parameter1,
2958 { "Parameter1", "iscsi.parameter1",
2959 FT_UINT16, BASE_HEX, NULL, 0,
2960 "Parameter 1", HFILL }
2962 { &hf_iscsi_Parameter2,
2963 { "Parameter2", "iscsi.parameter2",
2964 FT_UINT16, BASE_HEX, NULL, 0,
2965 "Parameter 2", HFILL }
2967 { &hf_iscsi_Parameter3,
2968 { "Parameter3", "iscsi.parameter3",
2969 FT_UINT16, BASE_HEX, NULL, 0,
2970 "Parameter 3", HFILL }
2972 { &hf_iscsi_Reject_Reason,
2973 { "Reason", "iscsi.reject.reason",
2974 FT_UINT8, BASE_HEX, VALS(iscsi_reject_reasons), 0,
2975 "Reason for command rejection", HFILL }
2977 { &hf_iscsi_snack_type,
2978 { "S", "iscsi.snack.type",
2979 FT_UINT8, BASE_DEC, VALS(iscsi_snack_types), 0x0f,
2980 "Type of SNACK requested", HFILL }
2983 { "BegRun", "iscsi.snack.begrun",
2984 FT_UINT32, BASE_HEX, NULL, 0,
2985 "First missed DataSN or StatSN", HFILL }
2987 { &hf_iscsi_RunLength,
2988 { "RunLength", "iscsi.snack.runlength",
2989 FT_UINT32, BASE_HEX, NULL, 0,
2990 "Number of additional missing status PDUs in this run", HFILL }
2994 /* Setup protocol subtree array */
2995 static gint *ett[] = {
2997 &ett_iscsi_KeyValues,
3000 &ett_iscsi_RejectHeader,
3002 /* #ifndef DRAFT08 */
3007 /* Register the protocol name and description */
3008 proto_iscsi = proto_register_protocol("iSCSI", "iSCSI", "iscsi");
3009 new_register_dissector("iscsi", dissect_iscsi_handle, proto_iscsi);
3011 /* Required function calls to register the header fields and
3013 proto_register_field_array(proto_iscsi, hf, array_length(hf));
3014 proto_register_subtree_array(ett, array_length(ett));
3016 iscsi_module = prefs_register_protocol(proto_iscsi, NULL);
3018 prefs_register_enum_preference(iscsi_module,
3021 "The iSCSI protocol version",
3022 &iscsi_protocol_version,
3023 iscsi_protocol_versions,
3026 prefs_register_bool_preference(iscsi_module,
3027 "desegment_iscsi_messages",
3028 "Reassemble iSCSI messages\nspanning multiple TCP segments",
3029 "Whether the iSCSI dissector should reassemble messages spanning multiple TCP segments."
3030 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
3033 prefs_register_bool_preference(iscsi_module,
3035 "Enable bogus pdu filter",
3036 "When enabled, packets that appear bogus are ignored",
3037 &enable_bogosity_filter);
3039 prefs_register_bool_preference(iscsi_module,
3040 "demand_good_f_bit",
3041 "Ignore packets with bad F bit",
3042 "Ignore packets that haven't set the F bit when they should have",
3043 &demand_good_f_bit);
3045 prefs_register_uint_preference(iscsi_module,
3046 "bogus_pdu_max_data_len",
3047 "Bogus pdu max data length threshold",
3048 "Treat packets whose data segment length is greater than this value as bogus",
3050 &bogus_pdu_data_length_threshold);
3052 range_convert_str(&global_iscsi_port_range, TCP_PORT_ISCSI_RANGE, MAX_TCP_PORT);
3053 prefs_register_range_preference(iscsi_module,
3055 "Target Ports Range",
3056 "Range of iSCSI target ports"
3057 "(default " TCP_PORT_ISCSI_RANGE ")",
3058 &global_iscsi_port_range, MAX_TCP_PORT);
3060 prefs_register_uint_preference(iscsi_module,
3061 "target_system_port",
3062 "Target system port",
3063 "System port number of iSCSI target",
3065 &iscsi_system_port);
3067 prefs_register_bool_preference(iscsi_module,
3068 "enable_data_digests",
3069 "Enable data digests",
3070 "When enabled, pdus are assumed to contain a data digest",
3071 &enableDataDigests);
3073 prefs_register_bool_preference(iscsi_module,
3074 "data_digest_is_crc32c",
3075 "Data digest is CRC32C",
3076 "When enabled, data digests are assumed to be CRC32C",
3077 &dataDigestIsCRC32);
3079 prefs_register_uint_preference(iscsi_module,
3082 "The size of a data digest (bytes)",
3086 /* Preference supported in older versions.
3087 Register them as obsolete. */
3088 prefs_register_obsolete_preference(iscsi_module,
3089 "version_03_compatible");
3090 prefs_register_obsolete_preference(iscsi_module,
3091 "bogus_pdu_max_digest_padding");
3092 prefs_register_obsolete_preference(iscsi_module,
3093 "header_digest_is_crc32c");
3094 prefs_register_obsolete_preference(iscsi_module,
3095 "header_digest_size");
3096 prefs_register_obsolete_preference(iscsi_module,
3097 "enable_header_digests");
3102 * If this dissector uses sub-dissector registration add a
3103 * registration routine.
3107 * This format is required because a script is used to find these
3108 * routines and create the code that calls these routines.
3111 proto_reg_handoff_iscsi(void)
3113 heur_dissector_add("tcp", dissect_iscsi_heur, proto_iscsi);
3115 iscsi_handle = new_create_dissector_handle(dissect_iscsi_handle, proto_iscsi);
3116 dissector_add_handle("tcp.port", iscsi_handle);