+/* TODO for the cases where one just can not autodetect whether header digest
+ is used or not we might need a new preference
+ HeaderDigest :
+ Automatic (default)
+ None
+ CRC32
+*/
+
/* packet-iscsi.c
* Routines for iSCSI dissection
* Copyright 2001, Eurologic and Mark Burton <markb@ordern.com>
*
* $Id$
*
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
# include "config.h"
#endif
-#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <epan/prefs.h>
#include <epan/conversation.h>
#include "packet-scsi.h"
-#include "epan/nstime.h"
+#include <epan/nstime.h>
+#include <epan/emem.h>
+#include <epan/crc32.h>
/* the absolute values of these constants don't matter as long as
* latter revisions of the protocol are assigned a larger number */
{ NULL, NULL, 0 }
};
+static const value_string ahs_type_vals[] = {
+ {1, "Extended CDB"},
+ {2, "Expected Bidirection Read Data Length"},
+ {0, NULL}
+};
+
+static dissector_handle_t iscsi_handle=NULL;
+
static gint iscsi_protocol_version = ISCSI_PROTOCOL_DRAFT13;
static gboolean iscsi_desegment = TRUE;
static int dataDigestIsCRC32 = TRUE;
-static int dataDigestSize = 4;
+static guint dataDigestSize = 4;
static guint iscsi_port = 3260;
static int hf_iscsi_data_out_frame = -1;
static int hf_iscsi_response_frame = -1;
static int hf_iscsi_AHS = -1;
+static int hf_iscsi_AHS_length = -1;
+static int hf_iscsi_AHS_type = -1;
+static int hf_iscsi_AHS_blob = -1;
+static int hf_iscsi_AHS_read_data_length = -1;
+static int hf_iscsi_AHS_extended_cdb = -1;
static int hf_iscsi_Padding = -1;
static int hf_iscsi_ping_data = -1;
static int hf_iscsi_immediate_data = -1;
static int hf_iscsi_write_data = -1;
static int hf_iscsi_read_data = -1;
static int hf_iscsi_error_pdu_data = -1;
-static int hf_iscsi_async_message_data = -1;
+static int hf_iscsi_async_event_data = -1;
static int hf_iscsi_vendor_specific_data = -1;
static int hf_iscsi_Opcode = -1;
static int hf_iscsi_Flags = -1;
#define ISCSI_HEADER_DIGEST_AUTO 0
#define ISCSI_HEADER_DIGEST_NONE 1
#define ISCSI_HEADER_DIGEST_CRC32 2
-/* this structure contains session wide state for all iscsi sessions */
+/* this structure contains session wide state for a specific tcp conversation */
typedef struct _iscsi_session_t {
- guint32 conv_idx; /* unique ID for conversation */
guint32 header_digest;
+ emem_tree_t *itlq; /* indexed by ITT */
+ emem_tree_t *itl; /* indexed by LUN */
} iscsi_session_t;
-static GHashTable *iscsi_session_table = NULL;
-static GMemChunk *iscsi_sessions = NULL;
-static gint
-iscsi_session_equal(gconstpointer v, gconstpointer w)
-{
- const iscsi_session_t *v1 = (const iscsi_session_t *)v;
- const iscsi_session_t *v2 = (const iscsi_session_t *)w;
-
- return (v1->conv_idx == v2->conv_idx);
-}
-
-static guint
-iscsi_session_hash (gconstpointer v)
-{
- const iscsi_session_t *key = (const iscsi_session_t *)v;
-
- return key->conv_idx;
-}
{5, "Logical Unit Reset"},
{6, "Target Warm Reset"},
{7, "Target Cold Reset"},
+ {8, "Target Reassign"},
{0, NULL},
};
{0, NULL},
};
-/*****************************************************************/
-/* */
-/* CRC LOOKUP TABLE */
-/* ================ */
-/* The following CRC lookup table was generated automagically */
-/* by the Rocksoft^tm Model CRC Algorithm Table Generation */
-/* Program V1.0 using the following model parameters: */
-/* */
-/* Width : 4 bytes. */
-/* Poly : 0x1EDC6F41L */
-/* Reverse : TRUE. */
-/* */
-/* For more information on the Rocksoft^tm Model CRC Algorithm, */
-/* see the document titled "A Painless Guide to CRC Error */
-/* Detection Algorithms" by Ross Williams */
-/* (ross@guest.adelaide.edu.au.). This document is likely to be */
-/* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft". */
-/* */
-/*****************************************************************/
-
-static guint32 crc32Table[256] = {
- 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
- 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
- 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
- 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
- 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
- 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
- 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
- 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
- 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
- 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
- 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
- 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
- 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
- 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
- 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
- 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
- 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
- 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
- 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
- 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
- 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
- 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
- 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
- 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
- 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
- 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
- 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
- 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
- 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
- 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
- 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
- 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
- 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
- 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
- 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
- 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
- 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
- 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
- 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
- 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
- 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
- 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
- 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
- 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
- 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
- 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
- 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
- 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
- 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
- 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
- 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
- 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
- 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
- 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
- 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
- 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
- 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
- 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
- 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
- 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
- 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
- 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
- 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
- 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L
-};
-
-#define CRC32C_PRELOAD 0xffffffff
-
-/*
- * Byte swap fix contributed by Dave Wysochanski <davidw@netapp.com>
- */
-#define CRC32C_SWAP(crc32c_value) \
- (((crc32c_value & 0xff000000) >> 24) | \
- ((crc32c_value & 0x00ff0000) >> 8) | \
- ((crc32c_value & 0x0000ff00) << 8) | \
- ((crc32c_value & 0x000000ff) << 24))
-
-static guint32
-calculateCRC32(const void *buf, int len, guint32 crc) {
- const guint8 *p = (const guint8 *)buf;
- crc = CRC32C_SWAP(crc);
- while(len-- > 0)
- crc = crc32Table[(crc ^ *p++) & 0xff] ^ (crc >> 8);
- return CRC32C_SWAP(crc);
-}
-
-
-
-
-
-/* structure and functions to keep track of
- * COMMAND/DATA_IN/DATA_OUT/RESPONSE matching
+/* structure and functions to keep track of
+ * COMMAND/DATA_IN/DATA_OUT/RESPONSE matching
*/
typedef struct _iscsi_conv_data {
- guint32 conv_idx;
- guint32 itt;
- guint32 request_frame;
guint32 data_in_frame;
guint32 data_out_frame;
- guint32 response_frame;
- guint32 iscsi_dl;
- nstime_t req_time;
+ itlq_nexus_t itlq;
} iscsi_conv_data_t;
-static GHashTable *iscsi_req_unmatched = NULL;
-static GHashTable *iscsi_req_matched = NULL;
-static GMemChunk *iscsi_req_vals = NULL;
-static guint32 iscsi_init_count = 200;
-
-static gint
-iscsi_equal_unmatched(gconstpointer v, gconstpointer w)
-{
- const iscsi_conv_data_t *v1 = (const iscsi_conv_data_t *)v;
- const iscsi_conv_data_t *v2 = (const iscsi_conv_data_t *)w;
-
- return (v1->conv_idx == v2->conv_idx)&&(v1->itt == v2->itt);
-}
-
-static guint
-iscsi_hash_unmatched (gconstpointer v)
-{
- const iscsi_conv_data_t *key = (const iscsi_conv_data_t *)v;
- guint val;
-
- val = key->conv_idx + key->itt;
-
- return val;
-}
-
-static gint
-iscsi_equal_matched(gconstpointer v, gconstpointer w)
-{
- const iscsi_conv_data_t *v1 = (const iscsi_conv_data_t *)v;
- const iscsi_conv_data_t *v2 = (const iscsi_conv_data_t *)w;
- int check_frame;
-
- check_frame=0;
- if (v1->request_frame && (v1->request_frame==v2->request_frame))
- check_frame=1;
- if (v1->data_in_frame && (v1->data_in_frame==v2->data_in_frame))
- check_frame=1;
- if (v1->data_out_frame && (v1->data_out_frame==v2->data_out_frame))
- check_frame=1;
- if (v1->response_frame && (v1->response_frame==v2->response_frame))
- check_frame=1;
-
- return check_frame&&(v1->conv_idx == v2->conv_idx)&&(v1->itt == v2->itt);
-}
-
-static guint
-iscsi_hash_matched (gconstpointer v)
-{
- const iscsi_conv_data_t *key = (const iscsi_conv_data_t *)v;
- guint val;
-
- val = key->conv_idx + key->itt;
-
- return val;
-}
-
-
-
-
-
-
-/*
- * Protocol initialization
- */
-static void
-iscsi_init_protocol(void)
-{
- if (iscsi_sessions) {
- g_mem_chunk_destroy(iscsi_sessions);
- iscsi_sessions=NULL;
- }
- if (iscsi_req_vals) {
- g_mem_chunk_destroy(iscsi_req_vals);
- iscsi_req_vals=NULL;
- }
- if (iscsi_req_unmatched) {
- g_hash_table_destroy(iscsi_req_unmatched);
- iscsi_req_unmatched=NULL;
- }
- if (iscsi_req_matched) {
- g_hash_table_destroy(iscsi_req_matched);
- iscsi_req_matched=NULL;
- }
- if (iscsi_session_table) {
- g_hash_table_destroy(iscsi_session_table);
- iscsi_session_table=NULL;
- }
-
- iscsi_req_unmatched = g_hash_table_new(iscsi_hash_unmatched, iscsi_equal_unmatched);
- iscsi_req_matched = g_hash_table_new(iscsi_hash_matched, iscsi_equal_matched);
- iscsi_session_table = g_hash_table_new(iscsi_session_hash, iscsi_session_equal);
- iscsi_req_vals = g_mem_chunk_new("iscsi_req_vals",
- sizeof(iscsi_conv_data_t),
- iscsi_init_count * sizeof(iscsi_conv_data_t),
- G_ALLOC_AND_FREE);
- iscsi_sessions = g_mem_chunk_new("iscsi_sessions",
- sizeof(iscsi_session_t),
- iscsi_init_count * sizeof(iscsi_session_t),
- G_ALLOC_AND_FREE);
-}
static int
iscsi_min(int a, int b) {
switch(iscsi_session->header_digest){
case ISCSI_HEADER_DIGEST_CRC32:
if(available_bytes >= (headerLen + 4)) {
- guint32 crc = ~calculateCRC32(tvb_get_ptr(tvb, offset, headerLen), headerLen, CRC32C_PRELOAD);
+ guint32 crc = ~crc32c_calculate(tvb_get_ptr(tvb, offset, headerLen), headerLen, CRC32C_PRELOAD);
guint32 sent = tvb_get_ntohl(tvb, offset + headerLen);
if(crc == sent) {
proto_tree_add_uint_format(ti, hf_iscsi_HeaderDigest32, tvb, offset + headerLen, 4, sent, "HeaderDigest: 0x%08x (Good CRC32)", sent);
} else {
proto_tree_add_uint_format(ti, hf_iscsi_HeaderDigest32, tvb, offset + headerLen, 4, sent, "HeaderDigest: 0x%08x (Bad CRC32, should be 0x%08x)", sent, crc);
-printf("bad digest\n");
}
}
return offset + headerLen + 4;
- break;
}
return offset + headerLen;
}
if(enableDataDigests) {
if(dataDigestIsCRC32) {
if(available_bytes >= (dataLen + 4)) {
- guint32 crc = ~calculateCRC32(tvb_get_ptr(tvb, offset, dataLen), dataLen, CRC32C_PRELOAD);
+ guint32 crc = ~crc32c_calculate(tvb_get_ptr(tvb, offset, dataLen), dataLen, CRC32C_PRELOAD);
guint32 sent = tvb_get_ntohl(tvb, offset + dataLen);
if(crc == sent) {
proto_tree_add_uint_format(ti, hf_iscsi_DataDigest32, tvb, offset + dataLen, 4, sent, "DataDigest: 0x%08x (Good CRC32)", sent);
}
return offset + dataLen + 4;
}
- if(available_bytes >= (dataLen + dataDigestSize)) {
+ if((unsigned)available_bytes >= (dataLen + dataDigestSize)) {
proto_tree_add_item(ti, hf_iscsi_DataDigest, tvb, offset + dataLen, dataDigestSize, FALSE);
}
return offset + dataLen + dataDigestSize;
/* Code to actually dissect the packets */
static void
-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) {
+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) {
guint original_offset = offset;
proto_tree *ti = NULL;
guint cdb_offset = offset + 32; /* offset of CDB from start of PDU */
guint end_offset = offset + tvb_length_remaining(tvb, offset);
iscsi_conv_data_t *cdata = NULL;
- scsi_task_id_t task_key;
int paddedDataSegmentLength = data_segment_len;
+ guint16 lun=0xffff;
+ guint immediate_data_length=0;
+ guint immediate_data_offset=0;
+ itl_nexus_t *itl=NULL;
+ guint ahs_cdb_length=0;
+ guint ahs_cdb_offset=0;
+ guint32 data_offset=0;
+
if(paddedDataSegmentLength & 3)
paddedDataSegmentLength += 4 - (paddedDataSegmentLength & 3);
/* Make entries in Protocol column and Info column on summary display */
- if (check_col(pinfo->cinfo, COL_PROTOCOL))
- col_set_str(pinfo->cinfo, COL_PROTOCOL, "iSCSI");
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "iSCSI");
+
+ /* XXX we need a way to handle replayed iscsi itt here */
+ cdata=(iscsi_conv_data_t *)se_tree_lookup32(iscsi_session->itlq, tvb_get_ntohl(tvb, offset+16));
+ if(!cdata){
+ cdata = se_alloc (sizeof(iscsi_conv_data_t));
+ cdata->itlq.lun=0xffff;
+ cdata->itlq.scsi_opcode=0xffff;
+ cdata->itlq.task_flags=0;
+ cdata->itlq.data_length=0;
+ cdata->itlq.bidir_data_length=0;
+ cdata->itlq.fc_time = pinfo->fd->abs_ts;
+ cdata->itlq.first_exchange_frame=0;
+ cdata->itlq.last_exchange_frame=0;
+ cdata->itlq.flags=0;
+ cdata->itlq.alloc_len=0;
+ cdata->itlq.extra_data=NULL;
+ cdata->data_in_frame=0;
+ cdata->data_out_frame=0;
+
+ se_tree_insert32(iscsi_session->itlq, tvb_get_ntohl(tvb, offset+16), cdata);
+ }
if (opcode == ISCSI_OPCODE_SCSI_RESPONSE ||
opcode == ISCSI_OPCODE_SCSI_DATA_IN) {
if ((opcode == ISCSI_OPCODE_SCSI_RESPONSE) ||
(opcode == ISCSI_OPCODE_SCSI_DATA_IN) ||
(opcode == ISCSI_OPCODE_SCSI_DATA_OUT)) {
- if (!pinfo->fd->flags.visited){
- iscsi_conv_data_t ckey;
- ckey.conv_idx = iscsi_session->conv_idx;
- ckey.itt = tvb_get_ntohl (tvb, offset+16);
-
- /* first time we see this packet. check if we can find the request */
- cdata = (iscsi_conv_data_t *)g_hash_table_lookup (iscsi_req_unmatched, &ckey);
- if (cdata){
- if (cdata->data_in_frame+cdata->data_out_frame+cdata->response_frame==0){
- /* this is the first response to the request, add it to the matched table */
- g_hash_table_insert (iscsi_req_matched, cdata, cdata);
- }
- switch(opcode){
- case ISCSI_OPCODE_SCSI_RESPONSE:
- cdata->response_frame=pinfo->fd->num;
- break;
- case ISCSI_OPCODE_SCSI_DATA_IN:
- /* a bit ugly but we need to check the S bit here */
- if(tvb_get_guint8(tvb, offset+1)&ISCSI_SCSI_DATA_FLAG_S){
- cdata->response_frame=pinfo->fd->num;
- }
- cdata->data_in_frame=pinfo->fd->num;
- break;
- case ISCSI_OPCODE_SCSI_DATA_OUT:
- cdata->data_out_frame=pinfo->fd->num;
- break;
- }
- }
- } else {
- iscsi_conv_data_t ckey;
- ckey.conv_idx = iscsi_session->conv_idx;
- ckey.itt = tvb_get_ntohl (tvb, offset+16);
- ckey.request_frame=0;
- ckey.data_in_frame=0;
- ckey.data_out_frame=0;
- ckey.response_frame=0;
- switch(opcode){
- case ISCSI_OPCODE_SCSI_RESPONSE:
- ckey.response_frame=pinfo->fd->num;
- break;
- case ISCSI_OPCODE_SCSI_DATA_IN:
- ckey.data_in_frame=pinfo->fd->num;
- break;
- case ISCSI_OPCODE_SCSI_DATA_OUT:
- ckey.data_out_frame=pinfo->fd->num;
- break;
+ /* first time we see this packet. check if we can find the request */
+ switch(opcode){
+ case ISCSI_OPCODE_SCSI_RESPONSE:
+ cdata->itlq.last_exchange_frame=pinfo->fd->num;
+ break;
+ case ISCSI_OPCODE_SCSI_DATA_IN:
+ /* a bit ugly but we need to check the S bit here */
+ if(tvb_get_guint8(tvb, offset+1)&ISCSI_SCSI_DATA_FLAG_S){
+ cdata->itlq.last_exchange_frame=pinfo->fd->num;
}
-
- /* we have seen this one before, pick it up from the matched table */
- cdata = (iscsi_conv_data_t *)g_hash_table_lookup (iscsi_req_matched, &ckey);
- }
-
- if (cdata){
- task_key.conv_id = cdata->conv_idx;
- task_key.task_id = cdata->itt;
- pinfo->private_data = &task_key;
- } else {
- pinfo->private_data = NULL;
+ cdata->data_in_frame=pinfo->fd->num;
+ break;
+ case ISCSI_OPCODE_SCSI_DATA_OUT:
+ cdata->data_out_frame=pinfo->fd->num;
+ break;
}
} else if (opcode == ISCSI_OPCODE_SCSI_COMMAND) {
- if (!pinfo->fd->flags.visited){
- iscsi_conv_data_t ckey;
-
- /* first time we see this packet. */
- /*check if we have seen this request before and delete it in that case */
- ckey.conv_idx = iscsi_session->conv_idx;
- ckey.itt = tvb_get_ntohl (tvb, offset+16);
- cdata = (iscsi_conv_data_t *)g_hash_table_lookup (iscsi_req_unmatched, &ckey);
- if (cdata){
- g_hash_table_remove(iscsi_req_unmatched, &ckey);
- }
-
- /* add this new transaction to the unmatched table */
- cdata = g_mem_chunk_alloc (iscsi_req_vals);
- cdata->conv_idx = iscsi_session->conv_idx;
- cdata->itt = tvb_get_ntohl (tvb, offset+16);
- cdata->request_frame=pinfo->fd->num;
- cdata->data_in_frame=0;
- cdata->data_out_frame=0;
- cdata->response_frame=0;
- cdata->req_time.nsecs = pinfo->fd->abs_usecs*1000;
- cdata->req_time.secs = pinfo->fd->abs_secs;
-
- g_hash_table_insert (iscsi_req_unmatched, cdata, cdata);
+ /*we need the LUN value for some of the commands so we can pass it
+ across to the SCSI dissector.
+ Not correct but simple and probably accurate enough :
+ If bit 6 of first bit is 0 then just take second byte as the LUN
+ If bit 6 of first bit is 1, then take 6 bits from first byte
+ and all of second byte and pretend it is the lun value
+ people that care can add host specific dissection of vsa later.
+
+ We need to keep track of this on a per transaction basis since
+ for error recoverylevel 0 and when the A bit is clear in a
+ Data-In PDU, there will not be a LUN field in teh iscsi layer.
+ */
+ if(tvb_get_guint8(tvb, offset+8)&0x40){
+ /* volume set addressing */
+ lun=tvb_get_guint8(tvb,offset+8)&0x3f;
+ lun<<=8;
+ lun|=tvb_get_guint8(tvb,offset+9);
} else {
- iscsi_conv_data_t ckey;
- ckey.conv_idx = iscsi_session->conv_idx;
- ckey.itt = tvb_get_ntohl (tvb, offset+16);
- ckey.request_frame=pinfo->fd->num;
- ckey.data_in_frame=0;
- ckey.data_out_frame=0;
- ckey.response_frame=0;
-
- /* we have seen this one before, pick it up from the matched table */
- cdata = (iscsi_conv_data_t *)g_hash_table_lookup (iscsi_req_matched, &ckey);
+ lun=tvb_get_guint8(tvb,offset+9);
}
+ cdata->itlq.lun=lun;
+ cdata->itlq.first_exchange_frame=pinfo->fd->num;
- if (cdata){
- /* The SCSI protocol uses this as the key to detect a
- * SCSI-level conversation. */
- task_key.conv_id = cdata->conv_idx;
- task_key.task_id = cdata->itt;
- pinfo->private_data = &task_key;
- } else {
- pinfo->private_data=NULL;
+ itl=(itl_nexus_t *)se_tree_lookup32(iscsi_session->itl, lun);
+ if(!itl){
+ itl=se_alloc(sizeof(itl_nexus_t));
+ itl->cmdset=0xff;
+ itl->conversation=conversation;
+ se_tree_insert32(iscsi_session->itl, lun, itl);
}
+
}
- else {
- pinfo->private_data = NULL;
+
+ if(!itl){
+ itl=(itl_nexus_t *)se_tree_lookup32(iscsi_session->itl, cdata->itlq.lun);
}
+
if (check_col(pinfo->cinfo, COL_INFO)) {
if (opcode != ISCSI_OPCODE_SCSI_COMMAND) {
proto_tree_add_boolean(ti, hf_iscsi_I, tvb, offset + 0, 1, b);
}
-
if(opcode == ISCSI_OPCODE_NOP_OUT) {
/* NOP Out */
if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
guint32 ahsLen = tvb_get_guint8(tvb, offset + 4) * 4;
{
gint b = tvb_get_guint8(tvb, offset + 1);
+
proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_F, tvb, offset + 1, 1, b);
proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_R, tvb, offset + 1, 1, b);
+ if(b&0x40){
+ cdata->itlq.task_flags|=SCSI_DATA_READ;
+ }
proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_W, tvb, offset + 1, 1, b);
+ if(b&0x20){
+ cdata->itlq.task_flags|=SCSI_DATA_WRITE;
+ }
proto_tree_add_uint(tt, hf_iscsi_SCSICommand_Attr, tvb, offset + 1, 1, b);
}
if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT12) {
proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_ExpectedDataTransferLength, tvb, offset + 20, 4, FALSE);
+ cdata->itlq.data_length=tvb_get_ntohl(tvb, offset+20);
proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
- {
- if(ahsLen > 0) {
- /* FIXME - disssect AHS? */
- proto_tree_add_item(ti, hf_iscsi_AHS, tvb, offset + 48, ahsLen, FALSE);
+ if(ahsLen > 0) {
+ guint ahs_offset=offset+48;
+ guint16 ahs_length=0;
+ guint8 ahs_type=0;
+
+ while(ahs_offset<(offset+48+ahsLen)){
+
+ ahs_length=tvb_get_ntohs(tvb, ahs_offset);
+ proto_tree_add_item(ti, hf_iscsi_AHS_length, tvb, ahs_offset, 2, FALSE);
+ ahs_offset+=2;
+
+ ahs_type=tvb_get_guint8(tvb, ahs_offset);
+ proto_tree_add_item(ti, hf_iscsi_AHS_type, tvb, ahs_offset, 1, FALSE);
+ ahs_offset++;
+
+ switch(ahs_type){
+ case 0x01: /* extended CDB */
+ /* additional cdb */
+ ahs_cdb_offset=ahs_offset+1;
+ ahs_cdb_length=ahs_length-1;
+ proto_tree_add_item(ti, hf_iscsi_AHS_extended_cdb, tvb, ahs_cdb_offset, ahs_cdb_length, FALSE);
+ ahs_offset+=ahs_length;
+ break;
+ case 0x02: /* bidirectional read data length */
+ /* skip reserved byte */
+ ahs_offset++;
+ /* read data length */
+ proto_tree_add_item(ti, hf_iscsi_AHS_read_data_length, tvb, ahs_offset, 4, FALSE);
+ cdata->itlq.bidir_data_length=tvb_get_ntohl(tvb, ahs_offset);
+ ahs_offset+=4;
+ break;
+ default:
+ proto_tree_add_item(ti, hf_iscsi_AHS_blob, tvb, ahs_offset, ahs_length, FALSE);
+ ahs_offset+=ahs_length;
+ }
+
+ /* strip off padding bytes */
+ if(ahs_offset&0x0003){
+ ahs_offset=(ahs_offset+3)&0xfffc;
+ }
+
}
- offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48 + ahsLen);
+
}
+ offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48 + ahsLen);
+
+ immediate_data_offset=offset;
offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_immediate_data);
+ immediate_data_length=offset-immediate_data_offset;
} else if(opcode == ISCSI_OPCODE_SCSI_RESPONSE) {
/* SCSI Response */
{
proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
+ data_offset=tvb_get_ntohl(tvb, offset+40);
+
offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
/* do not update offset here because the data segment is
* dissected below */
proto_tree_add_boolean(tt, hf_iscsi_SCSIData_U, tvb, offset + 1, 1, b);
proto_tree_add_boolean(tt, hf_iscsi_SCSIData_S, tvb, offset + 1, 1, b);
}
- proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Status, tvb, offset + 3, 1, FALSE);
+ if(S_bit){
+ proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Status, tvb, offset + 3, 1, FALSE);
+ }
if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
}
proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
+ data_offset=tvb_get_ntohl(tvb, offset+40);
+
if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
proto_tree_add_item(ti, hf_iscsi_SCSIData_ResidualCount, tvb, offset + 44, 4, FALSE);
}
proto_tree_add_item(ti, hf_iscsi_DesiredDataLength, tvb, offset + 44, 4, FALSE);
offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
} else if(opcode == ISCSI_OPCODE_ASYNC_MESSAGE) {
+ int dsl, snsl;
+
/* Asynchronous Message */
if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
}
+ dsl=tvb_get_ntoh24(tvb, offset+5);
proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_Parameter2, tvb, offset + 40, 2, FALSE);
proto_tree_add_item(ti, hf_iscsi_Parameter3, tvb, offset + 42, 2, FALSE);
offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
- offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_async_message_data);
+
+ /* If we have a datasegment this contains scsi sense info followed
+ * by iscsi event data. (rfc3720 10.9.4)
+ */
+ if(dsl){
+ snsl=tvb_get_ntohs(tvb, offset);
+ offset+=2;
+ if(snsl){
+ tvbuff_t *data_tvb;
+ int tvb_len, tvb_rlen;
+
+ tvb_len=tvb_length_remaining(tvb, offset);
+ if(tvb_len>snsl)
+ tvb_len=snsl;
+ tvb_rlen=tvb_reported_length_remaining(tvb, offset);
+ if(tvb_rlen>snsl)
+ tvb_rlen=snsl;
+ data_tvb=tvb_new_subset(tvb, offset, tvb_len, tvb_rlen);
+ dissect_scsi_snsinfo (data_tvb, pinfo, tree, 0,
+ tvb_len,
+ &cdata->itlq, itl);
+
+ offset+=snsl;
+ }
+ if((end_offset-offset)>0){
+ proto_tree_add_item(ti, hf_iscsi_async_event_data, tvb, offset, end_offset-offset, FALSE);
+ }
+ }
+ offset=end_offset;
} else if(opcode == ISCSI_OPCODE_REJECT) {
/* Reject */
proto_tree_add_item(ti, hf_iscsi_Reject_Reason, tvb, offset + 2, 1, FALSE);
/* handle request/response matching */
- if (cdata){
- switch(opcode){
- case ISCSI_OPCODE_SCSI_RESPONSE:
- if (cdata->request_frame){
- nstime_t delta_time;
- proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->request_frame);
- delta_time.secs = pinfo->fd->abs_secs - cdata->req_time.secs;
- delta_time.nsecs = pinfo->fd->abs_usecs*1000 - cdata->req_time.nsecs;
- if (delta_time.nsecs<0){
- delta_time.nsecs+=1000000000;
- delta_time.secs--;
- }
- proto_tree_add_time(ti, hf_iscsi_time, tvb, 0, 0, &delta_time);
-
- }
- if (cdata->data_in_frame)
- proto_tree_add_uint(ti, hf_iscsi_data_in_frame, tvb, 0, 0, cdata->data_in_frame);
- if (cdata->data_out_frame)
- proto_tree_add_uint(ti, hf_iscsi_data_out_frame, tvb, 0, 0, cdata->data_out_frame);
- break;
- case ISCSI_OPCODE_SCSI_DATA_IN:
- /* if we have phase collaps then we might have the
- response embedded in the last DataIn segment */
- if(!S_bit){
- if (cdata->request_frame)
- proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->request_frame);
- if (cdata->response_frame)
- proto_tree_add_uint(ti, hf_iscsi_response_frame, tvb, 0, 0, cdata->response_frame);
- } else {
- if (cdata->request_frame){
- nstime_t delta_time;
- proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->request_frame);
- delta_time.secs = pinfo->fd->abs_secs - cdata->req_time.secs;
- delta_time.nsecs = pinfo->fd->abs_usecs*1000 - cdata->req_time.nsecs;
- if (delta_time.nsecs<0){
- delta_time.nsecs+=1000000000;
- delta_time.secs--;
- }
- proto_tree_add_time(ti, hf_iscsi_time, tvb, 0, 0, &delta_time);
-
- }
+ switch(opcode){
+ case ISCSI_OPCODE_SCSI_RESPONSE:
+ if (cdata->itlq.first_exchange_frame){
+ nstime_t delta_time;
+ proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->itlq.first_exchange_frame);
+ nstime_delta(&delta_time, &pinfo->fd->abs_ts, &cdata->itlq.fc_time);
+ proto_tree_add_time(ti, hf_iscsi_time, tvb, 0, 0, &delta_time);
+ }
+ if (cdata->data_in_frame)
+ proto_tree_add_uint(ti, hf_iscsi_data_in_frame, tvb, 0, 0, cdata->data_in_frame);
+ if (cdata->data_out_frame)
+ proto_tree_add_uint(ti, hf_iscsi_data_out_frame, tvb, 0, 0, cdata->data_out_frame);
+ break;
+ case ISCSI_OPCODE_SCSI_DATA_IN:
+ /* if we have phase collaps then we might have the
+ response embedded in the last DataIn segment */
+ if(!S_bit){
+ if (cdata->itlq.first_exchange_frame)
+ proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->itlq.first_exchange_frame);
+ if (cdata->itlq.last_exchange_frame)
+ proto_tree_add_uint(ti, hf_iscsi_response_frame, tvb, 0, 0, cdata->itlq.last_exchange_frame);
+ } else {
+ if (cdata->itlq.first_exchange_frame){
+ nstime_t delta_time;
+ proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->itlq.first_exchange_frame);
+ nstime_delta(&delta_time, &pinfo->fd->abs_ts, &cdata->itlq.fc_time);
+ proto_tree_add_time(ti, hf_iscsi_time, tvb, 0, 0, &delta_time);
}
- if (cdata->data_out_frame)
- proto_tree_add_uint(ti, hf_iscsi_data_out_frame, tvb, 0, 0, cdata->data_out_frame);
- break;
- case ISCSI_OPCODE_SCSI_DATA_OUT:
- if (cdata->request_frame)
- proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->request_frame);
- if (cdata->data_in_frame)
- proto_tree_add_uint(ti, hf_iscsi_data_in_frame, tvb, 0, 0, cdata->data_in_frame);
- if (cdata->response_frame)
- proto_tree_add_uint(ti, hf_iscsi_response_frame, tvb, 0, 0, cdata->response_frame);
- break;
- case ISCSI_OPCODE_SCSI_COMMAND:
- if (cdata->data_in_frame)
- proto_tree_add_uint(ti, hf_iscsi_data_in_frame, tvb, 0, 0, cdata->data_in_frame);
- if (cdata->data_out_frame)
- proto_tree_add_uint(ti, hf_iscsi_data_out_frame, tvb, 0, 0, cdata->data_out_frame);
- if (cdata->response_frame)
- proto_tree_add_uint(ti, hf_iscsi_response_frame, tvb, 0, 0, cdata->response_frame);
- break;
}
+ if (cdata->data_out_frame)
+ proto_tree_add_uint(ti, hf_iscsi_data_out_frame, tvb, 0, 0, cdata->data_out_frame);
+ break;
+ case ISCSI_OPCODE_SCSI_DATA_OUT:
+ if (cdata->itlq.first_exchange_frame)
+ proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->itlq.first_exchange_frame);
+ if (cdata->data_in_frame)
+ proto_tree_add_uint(ti, hf_iscsi_data_in_frame, tvb, 0, 0, cdata->data_in_frame);
+ if (cdata->itlq.last_exchange_frame)
+ proto_tree_add_uint(ti, hf_iscsi_response_frame, tvb, 0, 0, cdata->itlq.last_exchange_frame);
+ break;
+ case ISCSI_OPCODE_SCSI_COMMAND:
+ if (cdata->data_in_frame)
+ proto_tree_add_uint(ti, hf_iscsi_data_in_frame, tvb, 0, 0, cdata->data_in_frame);
+ if (cdata->data_out_frame)
+ proto_tree_add_uint(ti, hf_iscsi_data_out_frame, tvb, 0, 0, cdata->data_out_frame);
+ if (cdata->itlq.last_exchange_frame)
+ proto_tree_add_uint(ti, hf_iscsi_response_frame, tvb, 0, 0, cdata->itlq.last_exchange_frame);
+ break;
}
if((opcode & ((iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08)?
~(X_BIT | I_BIT) :
~I_BIT)) == ISCSI_OPCODE_SCSI_COMMAND) {
+ tvbuff_t *cdb_tvb, *data_tvb;
+ int tvb_len, tvb_rlen;
+ guint8 scsi_opcode;
+
/* SCSI Command */
- dissect_scsi_cdb (tvb, pinfo, tree, cdb_offset, 16, SCSI_DEV_UNKNOWN);
+ tvb_len=tvb_length_remaining(tvb, cdb_offset);
+ tvb_rlen=tvb_reported_length_remaining(tvb, cdb_offset);
+ scsi_opcode=tvb_get_guint8(tvb, cdb_offset);
+ if(ahs_cdb_length && ahs_cdb_length<1024){
+ char *cdb_buf;
+
+ /* We have a variable length CDB where bytes >16 is transported
+ * in the AHS.
+ */
+ cdb_buf=g_malloc(16+ahs_cdb_length);
+ /* the 16 first bytes of the cdb */
+ tvb_memcpy(tvb, cdb_buf, cdb_offset, 16);
+ /* the remainder of the cdb from the ahs */
+ tvb_memcpy(tvb, cdb_buf+16, ahs_cdb_offset, ahs_cdb_length);
+
+ cdb_tvb = tvb_new_child_real_data(tvb, cdb_buf,
+ ahs_cdb_length+16,
+ ahs_cdb_length+16);
+ tvb_set_free_cb(cdb_tvb, g_free);
+
+ add_new_data_source(pinfo, cdb_tvb, "CDB+AHS");
+ } else {
+ if(tvb_len>16){
+ tvb_len=16;
+ }
+ if(tvb_rlen>16){
+ tvb_rlen=16;
+ }
+ cdb_tvb=tvb_new_subset(tvb, cdb_offset, tvb_len, tvb_rlen);
+ }
+ dissect_scsi_cdb(cdb_tvb, pinfo, tree, SCSI_DEV_UNKNOWN, &cdata->itlq, itl);
+ /* we dont want the immediata below to overwrite our CDB info */
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_set_fence(pinfo->cinfo, COL_INFO);
+ }
+ /* where there any ImmediateData ? */
+ if(immediate_data_length){
+ /* Immediate Data TVB */
+ tvb_len=tvb_length_remaining(tvb, immediate_data_offset);
+ if(tvb_len>(int)immediate_data_length)
+ tvb_len=immediate_data_length;
+ tvb_rlen=tvb_reported_length_remaining(tvb, immediate_data_offset);
+ if(tvb_rlen>(int)immediate_data_length)
+ tvb_rlen=immediate_data_length;
+ data_tvb=tvb_new_subset(tvb, immediate_data_offset, tvb_len, tvb_rlen);
+ dissect_scsi_payload (data_tvb, pinfo, tree,
+ TRUE,
+ &cdata->itlq, itl,
+ 0);
+ }
}
else if (opcode == ISCSI_OPCODE_SCSI_RESPONSE) {
if (scsi_status == 0x2) {
if(ti != NULL)
proto_tree_add_item(ti, hf_iscsi_SenseLength, tvb, offset, 2, FALSE);
offset += 2;
- if(senseLen > 0)
- dissect_scsi_snsinfo (tvb, pinfo, tree, offset,
- iscsi_min (senseLen,
- end_offset-offset));
+ if(senseLen > 0){
+ tvbuff_t *data_tvb;
+ int tvb_len, tvb_rlen;
+
+ tvb_len=tvb_length_remaining(tvb, offset);
+ if(tvb_len>senseLen)
+ tvb_len=senseLen;
+ tvb_rlen=tvb_reported_length_remaining(tvb, offset);
+ if(tvb_rlen>senseLen)
+ tvb_rlen=senseLen;
+ data_tvb=tvb_new_subset(tvb, offset, tvb_len, tvb_rlen);
+ dissect_scsi_snsinfo (data_tvb, pinfo, tree, 0,
+ tvb_len,
+ &cdata->itlq, itl);
+ }
}
}
else {
- dissect_scsi_rsp (tvb, pinfo, tree);
+ dissect_scsi_rsp(tvb, pinfo, tree, &cdata->itlq, itl, scsi_status);
}
}
else if ((opcode == ISCSI_OPCODE_SCSI_DATA_IN) ||
(opcode == ISCSI_OPCODE_SCSI_DATA_OUT)) {
+ tvbuff_t *data_tvb;
+ int tvb_len, tvb_rlen;
+
/* offset is setup correctly by the iscsi code for response above */
- dissect_scsi_payload (tvb, pinfo, tree, offset, FALSE,
- iscsi_min (data_segment_len, end_offset-offset));
+ tvb_len=tvb_length_remaining(tvb, offset);
+ if(tvb_len>(int)data_segment_len)
+ tvb_len=data_segment_len;
+ tvb_rlen=tvb_reported_length_remaining(tvb, offset);
+ if(tvb_rlen>(int)data_segment_len)
+ tvb_rlen=data_segment_len;
+ data_tvb=tvb_new_subset(tvb, offset, tvb_len, tvb_rlen);
+ dissect_scsi_payload (data_tvb, pinfo, tree,
+ (opcode==ISCSI_OPCODE_SCSI_DATA_OUT),
+ &cdata->itlq, itl,
+ data_offset);
+ }
+
+ if(S_bit){
+ dissect_scsi_rsp(tvb, pinfo, tree, &cdata->itlq, itl, scsi_status);
}
}
/* Set up structures needed to add the protocol subtree and manage it */
guint iSCSIPdusDissected = 0;
guint offset = 0;
- guint32 available_bytes = tvb_length_remaining(tvb, offset);
- guint32 pduLen = 48;
+ guint32 available_bytes = tvb_length(tvb);
int digestsActive = 1;
conversation_t *conversation = NULL;
iscsi_session_t *iscsi_session=NULL;
+ guint8 opcode, tmpbyte;
+
+ if (available_bytes < 48 ){
+ /* heuristic already rejected the packet if size < 48,
+ assume it's an iscsi packet with a segmented header */
+ pinfo->desegment_offset = offset;
+ pinfo->desegment_len = 48 - available_bytes;
+ return TRUE;
+ }
- /* quick check to see if the packet is long enough to contain the
- * minimum amount of information we need */
- if (available_bytes < 48 && (!iscsi_desegment || available_bytes < 8)) {
- /* no, so give up */
+ opcode = tvb_get_guint8(tvb, offset + 0);
+ opcode &= OPCODE_MASK;
+
+ /* heuristics to verify that the packet looks sane. the heuristics
+ * are based on the RFC version of iscsi.
+ * (we should retire support for older iscsi versions in wireshark)
+ * -- ronnie s
+ */
+ /* opcode must be any of the ones from the standard
+ * also check the header that it looks "sane"
+ * all reserved or undefined bits in iscsi must be set to zero.
+ */
+ switch(opcode){
+ case ISCSI_OPCODE_NOP_IN:
+ /* top two bits of byte 0 must be 0 */
+ if(tvb_get_guint8(tvb, offset+0)&0xc0){
+ return FALSE;
+ }
+ /* byte 1 must be 0x80 */
+ if(tvb_get_guint8(tvb, offset+1)!=0x80){
+ return FALSE;
+ }
+ /* bytes 2 and 3 must be 0 */
+ if(tvb_get_guint8(tvb, offset+2)||tvb_get_guint8(tvb, offset+3)){
+ return FALSE;
+ }
+ break;
+ case ISCSI_OPCODE_NOP_OUT:
+ /* top bit of byte 0 must be 0 */
+ if(tvb_get_guint8(tvb, offset+0)&0x80){
+ return FALSE;
+ }
+ /* byte 1 must be 0x80 */
+ if(tvb_get_guint8(tvb, offset+1)!=0x80){
+ return FALSE;
+ }
+ /* bytes 2 and 3 must be 0 */
+ if(tvb_get_guint8(tvb, offset+2)||tvb_get_guint8(tvb, offset+3)){
+ return FALSE;
+ }
+ /* assume ITT and TTT must always be non NULL (ok they can be NULL
+ * from time to time but it usually means we are in the middle
+ * of a zeroed datablock).
+ */
+ if(!tvb_get_letohl(tvb,offset+16) || !tvb_get_letohl(tvb,offset+20)){
+ return FALSE;
+ }
+ /* all reserved bytes between 32 - 47 must be null */
+ if(tvb_get_letohl(tvb,offset+32)
+ || tvb_get_letohl(tvb,offset+36)
+ || tvb_get_letohl(tvb,offset+40)
+ || tvb_get_letohl(tvb,offset+44)){
+ return FALSE;
+ }
+ break;
+ case ISCSI_OPCODE_LOGIN_COMMAND:
+ /* top two bits in byte 0 must be 0x40 */
+ if((tvb_get_guint8(tvb, offset+0)&0xc0)!=0x40){
+
+ return FALSE;
+ }
+ /* both the T and C bits can not be set
+ * and the two reserved bits in byte 1 must be 0
+ */
+ tmpbyte=tvb_get_guint8(tvb, offset+1);
+ switch(tmpbyte&0xf0){
+ case 0x80:
+ case 0x40:
+ case 0x00:
+ break;
+ default:
+ return FALSE;
+ }
+ /* CSG and NSG must not be 2 */
+ if(((tmpbyte&0x03)==0x02)
+ || ((tmpbyte&0xc0)==0x08)){
+ return FALSE;
+ }
+ /* if T bit is set NSG must not be 0 */
+ if(tmpbyte&0x80){
+ if(!(tmpbyte&0x03)){
+ return FALSE;
+ }
+ }
+ /* should we test that datasegmentlen is non zero? */
+ break;
+ case ISCSI_OPCODE_LOGIN_RESPONSE:
+ /* top two bits in byte 0 must be 0 */
+ if(tvb_get_guint8(tvb, offset+0)&0xc0){
+
+ return FALSE;
+ }
+ /* both the T and C bits can not be set
+ * and the two reserved bits in byte 1 must be 0
+ */
+ tmpbyte=tvb_get_guint8(tvb, offset+1);
+ switch(tmpbyte&0xf0){
+ case 0x80:
+ case 0x40:
+ case 0x00:
+ break;
+ default:
+ return FALSE;
+ }
+ /* CSG and NSG must not be 2 */
+ if(((tmpbyte&0x03)==0x02)
+ || ((tmpbyte&0xc0)==0x08)){
+ return FALSE;
+ }
+ /* if T bit is set NSG must not be 0 */
+ if(tmpbyte&0x80){
+ if(!(tmpbyte&0x03)){
+ return FALSE;
+ }
+ }
+ /* the 32bit words at offsets 20, 40, 44 must be zero */
+ if(tvb_get_letohl(tvb,offset+20)
+ || tvb_get_letohl(tvb,offset+40)
+ || tvb_get_letohl(tvb,offset+44)){
+ return FALSE;
+ }
+ /* the two bytes at offset 38 must be zero */
+ if(tvb_get_letohs(tvb,offset+38)){
+ return FALSE;
+ }
+ /* should we test that datasegmentlen is non zero unless we just
+ * entered full featured phase?
+ */
+ break;
+ case ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION:
+ /* top bit in byte 0 must be 0 */
+ if(tvb_get_guint8(tvb, offset+0)&0x80){
+ return FALSE;
+ }
+ /* top bit in byte 1 must be set */
+ tmpbyte=tvb_get_guint8(tvb, offset+1);
+ if(!(tmpbyte&0x80)){
+ return FALSE;
+ }
+ /* Function must be known */
+ if(!match_strval(tmpbyte&0x7f, iscsi_task_management_functions)){
+ return FALSE;
+ }
+ /* bytes 2,3 must be null */
+ if(tvb_get_letohs(tvb,offset+2)){
+ return FALSE;
+ }
+ /* ahs and dsl must be null */
+ if(tvb_get_letohl(tvb,offset+4)){
+ return FALSE;
+ }
+ break;
+ case ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE:
+ /* top two bits in byte 0 must be 0 */
+ if(tvb_get_guint8(tvb, offset+0)&0xc0){
+ return FALSE;
+ }
+ /* byte 1 must be 0x80 */
+ if(tvb_get_guint8(tvb, offset+1)!=0x80){
+ return FALSE;
+ }
+ /* response must be 0-6 or 255 */
+ tmpbyte=tvb_get_guint8(tvb,offset+2);
+ if(tmpbyte>6 && tmpbyte<255){
+ return FALSE;
+ }
+ /* byte 3 must be 0 */
+ if(tvb_get_guint8(tvb,offset+3)){
+ return FALSE;
+ }
+ /* ahs and dsl as well as the 32bit words at offsets 8, 12, 20, 36
+ * 40, 44 must all be 0
+ */
+ if(tvb_get_letohl(tvb,offset+4)
+ || tvb_get_letohl(tvb,offset+8)
+ || tvb_get_letohl(tvb,offset+12)
+ || tvb_get_letohl(tvb,offset+20)
+ || tvb_get_letohl(tvb,offset+36)
+ || tvb_get_letohl(tvb,offset+40)
+ || tvb_get_letohl(tvb,offset+44)){
+ return FALSE;
+ }
+ break;
+ case ISCSI_OPCODE_LOGOUT_COMMAND:
+ /* top bit in byte 0 must be 0 */
+ if(tvb_get_guint8(tvb, offset+0)&0x80){
+ return FALSE;
+ }
+ /* top bit in byte 1 must be set */
+ tmpbyte=tvb_get_guint8(tvb, offset+1);
+ if(!(tmpbyte&0x80)){
+ return FALSE;
+ }
+ /* Reason code must be known */
+ if(!match_strval(tmpbyte&0x7f, iscsi_logout_reasons)){
+ return FALSE;
+ }
+ /* bytes 2,3 must be null */
+ if(tvb_get_letohs(tvb,offset+2)){
+ return FALSE;
+ }
+ /* ahs and dsl as well as the 32bit words at offsets 8, 12, 32, 36
+ * 40, 44 must all be 0
+ */
+ if(tvb_get_letohl(tvb,offset+4)
+ || tvb_get_letohl(tvb,offset+8)
+ || tvb_get_letohl(tvb,offset+12)
+ || tvb_get_letohl(tvb,offset+32)
+ || tvb_get_letohl(tvb,offset+36)
+ || tvb_get_letohl(tvb,offset+40)
+ || tvb_get_letohl(tvb,offset+44)){
+ return FALSE;
+ }
+ break;
+ case ISCSI_OPCODE_SNACK_REQUEST:
+ /* top two bits in byte 0 must be 0 */
+ if(tvb_get_guint8(tvb, offset+0)&0xc0){
+ return FALSE;
+ }
+ /* top 4 bits in byte 1 must be 0x80 */
+ tmpbyte=tvb_get_guint8(tvb, offset+1);
+ if((tmpbyte&0xf0)!=0x80){
+ return FALSE;
+ }
+ /* type must be known */
+ if(!match_strval(tmpbyte&0x0f, iscsi_snack_types)){
+ return FALSE;
+ }
+ /* for status/snack and datack itt must be 0xffffffff
+ * for rdata/snack ttt must not be 0 or 0xffffffff
+ */
+ switch(tmpbyte&0x0f){
+ case 1:
+ case 2:
+ if(tvb_get_letohl(tvb,offset+16)!=0xffffffff){
+ return FALSE;
+ }
+ break;
+ case 3:
+ if(tvb_get_letohl(tvb,offset+20)==0xffffffff){
+ return FALSE;
+ }
+ if(tvb_get_letohl(tvb,offset+20)==0){
+ return FALSE;
+ }
+ break;
+ }
+ /* bytes 2,3 must be null */
+ if(tvb_get_letohs(tvb,offset+2)){
+ return FALSE;
+ }
+ /* the 32bit words at offsets 24, 32, 36
+ * must all be 0
+ */
+ if(tvb_get_letohl(tvb,offset+24)
+ || tvb_get_letohl(tvb,offset+32)
+ || tvb_get_letohl(tvb,offset+36)){
+ return FALSE;
+ }
+
+ break;
+ case ISCSI_OPCODE_R2T:
+ /* top two bits in byte 0 must be 0 */
+ if(tvb_get_guint8(tvb, offset+0)&0xc0){
+ return FALSE;
+ }
+ /* byte 1 must be 0x80 */
+ if(tvb_get_guint8(tvb, offset+1)!=0x80){
+ return FALSE;
+ }
+ /* bytes 2,3 must be null */
+ if(tvb_get_letohs(tvb,offset+2)){
+ return FALSE;
+ }
+ /* ahs and dsl must be null */
+ if(tvb_get_letohl(tvb,offset+4)){
+ return FALSE;
+ }
+ /* desired data transfer length must not be null */
+ if(!tvb_get_letohl(tvb,offset+44)){
+ return FALSE;
+ }
+ break;
+ case ISCSI_OPCODE_REJECT:
+ /* top two bits in byte 0 must be 0 */
+ if(tvb_get_guint8(tvb, offset+0)&0xc0){
+ return FALSE;
+ }
+ /* byte 1 must be 0x80 */
+ if(tvb_get_guint8(tvb, offset+1)!=0x80){
+ return FALSE;
+ }
+ /* reason must be known */
+ if(!match_strval(tvb_get_guint8(tvb,offset+2), iscsi_reject_reasons)){
+ return FALSE;
+ }
+ /* byte 3 must be 0 */
+ if(tvb_get_guint8(tvb, offset+3)){
+ return FALSE;
+ }
+ /* the 32bit words at offsets 8, 12, 20, 40, 44
+ * must all be 0
+ */
+ if(tvb_get_letohl(tvb,offset+8)
+ || tvb_get_letohl(tvb,offset+12)
+ || tvb_get_letohl(tvb,offset+20)
+ || tvb_get_letohl(tvb,offset+40)
+ || tvb_get_letohl(tvb,offset+44)){
+ return FALSE;
+ }
+ /* the 32bit word at 16 must be 0xffffffff */
+ if(tvb_get_letohl(tvb,offset+16)!=0xffffffff){
+ return FALSE;
+ }
+ break;
+ case ISCSI_OPCODE_TEXT_COMMAND:
+ /* top bit in byte 0 must be 0 */
+ if(tvb_get_guint8(tvb, offset+0)&0x80){
+ return FALSE;
+ }
+ /* one of the F and C bits must be set but not both
+ * low 6 bits in byte 1 must be 0
+ */
+ switch(tvb_get_guint8(tvb,offset+1)){
+ case 0x80:
+ case 0x40:
+ break;
+ default:
+ return FALSE;
+ }
+ /* bytes 2,3 must be null */
+ if(tvb_get_letohs(tvb,offset+2)){
+ return FALSE;
+ }
+ /* the 32bit words at offsets 32, 36, 40, 44
+ * must all be 0
+ */
+ if(tvb_get_letohl(tvb,offset+32)
+ || tvb_get_letohl(tvb,offset+36)
+ || tvb_get_letohl(tvb,offset+40)
+ || tvb_get_letohl(tvb,offset+44)){
+ return FALSE;
+ }
+ break;
+ case ISCSI_OPCODE_TEXT_RESPONSE:
+ /* top two bits in byte 0 must be 0 */
+ if(tvb_get_guint8(tvb, offset+0)&0xc0){
+ return FALSE;
+ }
+ /* one of the F and C bits must be set but not both
+ * low 6 bits in byte 1 must be 0
+ */
+ switch(tvb_get_guint8(tvb,offset+1)){
+ case 0x80:
+ case 0x40:
+ break;
+ default:
+ return FALSE;
+ }
+ /* bytes 2,3 must be null */
+ if(tvb_get_letohs(tvb,offset+2)){
+ return FALSE;
+ }
+ /* the 32bit words at offsets 36, 40, 44
+ * must all be 0
+ */
+ if(tvb_get_letohl(tvb,offset+36)
+ || tvb_get_letohl(tvb,offset+40)
+ || tvb_get_letohl(tvb,offset+44)){
+ return FALSE;
+ }
+ break;
+ case ISCSI_OPCODE_SCSI_COMMAND:
+ /* top bit in byte 0 must be 0 */
+ if(tvb_get_guint8(tvb, offset+0)&0x80){
+ return FALSE;
+ }
+ /* reserved bits in byte 1 must be 0 */
+ if(tvb_get_guint8(tvb, offset+1)&0x18){
+ return FALSE;
+ }
+ /* bytes 2,3 must be null */
+ if(tvb_get_letohs(tvb,offset+2)){
+ return FALSE;
+ }
+ /* last 6 bytes of LUN are always 0 */
+ if(tvb_get_ntohs(tvb, offset+10) || tvb_get_ntohl(tvb, offset+12)){
+ return FALSE;
+ }
+ /* expected data transfer length is never >16MByte ? */
+ if(tvb_get_guint8(tvb,offset+20)){
+ return FALSE;
+ }
+ break;
+ case ISCSI_OPCODE_SCSI_RESPONSE:
+ /* top two bits in byte 0 must be 0 */
+ if(tvb_get_guint8(tvb, offset+0)&0xc0){
+ return FALSE;
+ }
+ /* top bit in byte 1 must be 1 */
+ tmpbyte=tvb_get_guint8(tvb,offset+1);
+ if(!(tmpbyte&0x80)){
+ return FALSE;
+ }
+ /* the reserved bits in byte 1 must be 0 */
+ if(tmpbyte&0x61){
+ return FALSE;
+ }
+ /* status must be known */
+ if(!match_strval(tvb_get_guint8(tvb,offset+3), scsi_status_val)){
+ return FALSE;
+ }
+ /* the 32bit words at offsets 8, 12
+ * must all be 0
+ */
+ if(tvb_get_letohl(tvb,offset+8)
+ || tvb_get_letohl(tvb,offset+12)){
+ return FALSE;
+ }
+ break;
+ case ISCSI_OPCODE_ASYNC_MESSAGE:
+ /* top two bits in byte 0 must be 0 */
+ if(tvb_get_guint8(tvb, offset+0)&0xc0){
+ return FALSE;
+ }
+ /* byte 1 must be 0x80 */
+ if(tvb_get_guint8(tvb, offset+1)!=0x80){
+ return FALSE;
+ }
+ /* bytes 2,3 must be null */
+ if(tvb_get_letohs(tvb,offset+2)){
+ return FALSE;
+ }
+ /* the 32bit words at offsets 20, 44
+ * must all be 0
+ */
+ if(tvb_get_letohl(tvb,offset+20)
+ || tvb_get_letohl(tvb,offset+44)){
+ return FALSE;
+ }
+ /* the 32bit word at 16 must be 0xffffffff */
+ if(tvb_get_letohl(tvb,offset+16)!=0xffffffff){
+ return FALSE;
+ }
+ break;
+ case ISCSI_OPCODE_LOGOUT_RESPONSE:
+ /* top two bits in byte 0 must be 0 */
+ if(tvb_get_guint8(tvb, offset+0)&0xc0){
+ return FALSE;
+ }
+ /* byte 1 must be 0x80 */
+ if(tvb_get_guint8(tvb, offset+1)!=0x80){
+ return FALSE;
+ }
+ /* response must be known */
+ if(!match_strval(tvb_get_guint8(tvb,offset+2), iscsi_logout_response)){
+ return FALSE;
+ }
+ /* byte 3 must be 0 */
+ if(tvb_get_guint8(tvb,offset+3)){
+ return FALSE;
+ }
+ /* ahs and dsl as well as the 32bit words at offsets 8, 12, 20, 36
+ * 44 must all be 0
+ */
+ if(tvb_get_letohl(tvb,offset+4)
+ || tvb_get_letohl(tvb,offset+8)
+ || tvb_get_letohl(tvb,offset+12)
+ || tvb_get_letohl(tvb,offset+20)
+ || tvb_get_letohl(tvb,offset+36)
+ || tvb_get_letohl(tvb,offset+44)){
+ return FALSE;
+ }
+ break;
+ case ISCSI_OPCODE_SCSI_DATA_OUT:
+ /* top two bits in byte 0 must be 0 */
+ if(tvb_get_guint8(tvb, offset+0)&0xc0){
+ return FALSE;
+ }
+ /* low 7 bits in byte 1 must be 0 */
+ if(tvb_get_guint8(tvb,offset+1)&0x7f){
+ return FALSE;
+ }
+ /* bytes 2,3 must be null */
+ if(tvb_get_letohs(tvb,offset+2)){
+ return FALSE;
+ }
+ /* the 32bit words at offsets 24, 32, 44
+ * must all be 0
+ */
+ if(tvb_get_letohl(tvb,offset+24)
+ || tvb_get_letohl(tvb,offset+32)
+ || tvb_get_letohl(tvb,offset+44)){
+ return FALSE;
+ }
+ break;
+ case ISCSI_OPCODE_SCSI_DATA_IN:
+ /* top two bits in byte 0 must be 0 */
+ if(tvb_get_guint8(tvb, offset+0)&0xc0){
+ return FALSE;
+ }
+ /* reserved bits in byte 1 must be 0 */
+ if(tvb_get_guint8(tvb,offset+1)&0x38){
+ return FALSE;
+ }
+ /* byte 2 must be reserved */
+ if(tvb_get_guint8(tvb,offset+2)){
+ return FALSE;
+ }
+ break;
+ case ISCSI_OPCODE_VENDOR_SPECIFIC_I0:
+ case ISCSI_OPCODE_VENDOR_SPECIFIC_I1:
+ case ISCSI_OPCODE_VENDOR_SPECIFIC_I2:
+ case ISCSI_OPCODE_VENDOR_SPECIFIC_T0:
+ case ISCSI_OPCODE_VENDOR_SPECIFIC_T1:
+ case ISCSI_OPCODE_VENDOR_SPECIFIC_T2:
+ break;
+ default:
return FALSE;
}
+
/* process multiple iSCSI PDUs per packet */
while(available_bytes >= 48 || (iscsi_desegment && available_bytes >= 8)) {
const char *opcode_str = NULL;
guint32 data_segment_len;
- guint8 opcode = tvb_get_guint8(tvb, offset + 0);
+ guint32 pduLen = 48;
guint8 secondPduByte = tvb_get_guint8(tvb, offset + 1);
int badPdu = FALSE;
+ guint8 ahsLen=0;
/* mask out any extra bits in the opcode byte */
+ opcode = tvb_get_guint8(tvb, offset + 0);
opcode &= OPCODE_MASK;
opcode_str = match_strval(opcode, iscsi_opcodes);
badPdu = TRUE;
} else if(opcode==ISCSI_OPCODE_NOP_OUT) {
/* TransferTag for NOP-Out should either be -1 or
- the tag value we want for a response.
+ the tag value we want for a response.
Assume 0 means we are just inside a big all zero
datablock.
*/
if(opcode == ISCSI_OPCODE_SCSI_COMMAND) {
/* ahsLen */
- pduLen += tvb_get_guint8(tvb, offset + 4) * 4;
+ ahsLen = tvb_get_guint8(tvb, offset + 4);
+ pduLen += ahsLen * 4;
}
pduLen += data_segment_len;
if((pduLen & 3) != 0)
pduLen += 4 - (pduLen & 3);
- if(digestsActive) {
- pduLen += 4;
- }
if(digestsActive && data_segment_len > 0 && enableDataDigests) {
if(dataDigestIsCRC32)
}
/* make sure we have a conversation for this session */
- conversation = find_conversation (&pinfo->src, &pinfo->dst,
+ conversation = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst,
pinfo->ptype, pinfo->srcport,
pinfo->destport, 0);
if (!conversation) {
- conversation = conversation_new (&pinfo->src, &pinfo->dst,
+ conversation = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst,
pinfo->ptype, pinfo->srcport,
pinfo->destport, 0);
- iscsi_session=g_mem_chunk_alloc(iscsi_sessions);
- iscsi_session->conv_idx=conversation->index;
- iscsi_session->header_digest=ISCSI_HEADER_DIGEST_AUTO;
- g_hash_table_insert(iscsi_session_table, iscsi_session, iscsi_session);
}
+ iscsi_session=conversation_get_proto_data(conversation, proto_iscsi);
if(!iscsi_session){
- iscsi_session_t key;
- key.conv_idx=conversation->index;
- /* this should never return NULL */
- iscsi_session = (iscsi_session_t *)g_hash_table_lookup (iscsi_session_table, &key);
- if(!iscsi_session){
- iscsi_session=g_mem_chunk_alloc(iscsi_sessions);
- iscsi_session->conv_idx=conversation->index;
- iscsi_session->header_digest=ISCSI_HEADER_DIGEST_AUTO;
- g_hash_table_insert(iscsi_session_table, iscsi_session, iscsi_session);
- }
+ iscsi_session=se_alloc(sizeof(iscsi_session_t));
+ iscsi_session->header_digest=ISCSI_HEADER_DIGEST_AUTO;
+ iscsi_session->itlq=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "iSCSI ITLQ");
+ iscsi_session->itl=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "iSCSI ITL");
+ conversation_add_proto_data(conversation, proto_iscsi, iscsi_session);
+
+ /* DataOut PDUs are often mistaken by DCERPC heuristics to be
+ * that protocol. Now that we know this is iscsi, set a
+ * dissector for this conversation to block other heuristic
+ * dissectors.
+ */
+ conversation_set_dissector(conversation, iscsi_handle);
}
/* try to autodetect if header digest is used or not */
- if(digestsActive && (available_bytes>=52) && (iscsi_session->header_digest==ISCSI_HEADER_DIGEST_AUTO) ){
+ if(digestsActive && (available_bytes>=(guint32) (48+4+ahsLen*4)) && (iscsi_session->header_digest==ISCSI_HEADER_DIGEST_AUTO) ){
guint32 crc;
/* we have enough data to test if HeaderDigest is enabled */
- crc= ~calculateCRC32(tvb_get_ptr(tvb, offset, 48), 48, CRC32C_PRELOAD);
- if(crc==tvb_get_ntohl(tvb,48)){
+ crc= ~crc32c_calculate(tvb_get_ptr(tvb, offset, 48+ahsLen*4), 48+ahsLen*4, CRC32C_PRELOAD);
+ if(crc==tvb_get_ntohl(tvb,48+ahsLen*4)){
iscsi_session->header_digest=ISCSI_HEADER_DIGEST_CRC32;
} else {
iscsi_session->header_digest=ISCSI_HEADER_DIGEST_NONE;
}
+ /* Add header digest length to pdulen */
+ if(digestsActive){
+ switch(iscsi_session->header_digest){
+ case ISCSI_HEADER_DIGEST_CRC32:
+ pduLen += 4;
+ break;
+ case ISCSI_HEADER_DIGEST_NONE:
+ break;
+ case ISCSI_HEADER_DIGEST_AUTO:
+ /* oops we didnt know what digest is used yet */
+ /* here we should use some default */
+ break;
+ default:
+ DISSECTOR_ASSERT_NOT_REACHED();
+ }
+ }
+
/*
* Desegmentation check.
*/
}
/* This is to help TCP keep track of PDU boundaries
- and allows it to find PDUs that are not aligned to
+ and allows it to find PDUs that are not aligned to
the start of a TCP segments.
Since it also allows TCP to know what is in the middle
of a large PDU, it reduces the probability of a segment
col_append_str(pinfo->cinfo, COL_INFO, ", ");
}
- dissect_iscsi_pdu(tvb, pinfo, tree, offset, opcode, opcode_str, data_segment_len, iscsi_session);
+ dissect_iscsi_pdu(tvb, pinfo, tree, offset, opcode, opcode_str, data_segment_len, iscsi_session, conversation);
if(pduLen > available_bytes)
pduLen = available_bytes;
offset += pduLen;
this to be iSCSI using "Decode As..."
In this case we will not check the port number for sanity and just
do as the user said.
+ We still check that the PDU header looks sane though.
*/
-static void
+static int
dissect_iscsi_handle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
- dissect_iscsi(tvb, pinfo, tree, FALSE);
+ return dissect_iscsi(tvb, pinfo, tree, FALSE);
}
/* This is called through the heuristic handler.
*/
static gboolean
dissect_iscsi_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
+ guint32 available_bytes = tvb_length(tvb);
+
+ /* quick check to see if the packet is long enough to contain the
+ * minimum amount of information we need */
+ if (available_bytes < 48 ){
+ /* no, so give up */
+ return FALSE;
+ }
+
return dissect_iscsi(tvb, pinfo, tree, TRUE);
}
-/* Register the protocol with Ethereal */
+/* Register the protocol with Wireshark */
/*
* this format is require because a script is used to build the C
{ &hf_iscsi_AHS,
{ "AHS", "iscsi.ahs",
- FT_BYTES, BASE_HEX, NULL, 0,
+ FT_BYTES, BASE_NONE, NULL, 0,
"Additional header segment", HFILL }
},
+ { &hf_iscsi_AHS_length,
+ { "AHS Length", "iscsi.ahs.length",
+ FT_UINT16, BASE_DEC, NULL, 0,
+ "Length of Additional header segment", HFILL }
+ },
+ { &hf_iscsi_AHS_read_data_length,
+ { "Bidirectional Read Data Length", "iscsi.ahs.bidir.length",
+ FT_UINT32, BASE_DEC, NULL, 0,
+ NULL, HFILL }
+ },
+ { &hf_iscsi_AHS_type,
+ { "AHS Type", "iscsi.ahs.type",
+ FT_UINT8, BASE_DEC, VALS(ahs_type_vals), 0,
+ "Type of Additional header segment", HFILL }
+ },
+ { &hf_iscsi_AHS_extended_cdb,
+ { "AHS Extended CDB", "iscsi.ahs.extended_cdb",
+ FT_BYTES, BASE_NONE, NULL, 0,
+ NULL, HFILL }
+ },
+ { &hf_iscsi_AHS_blob,
+ { "Unknown AHS blob", "iscsi.ahs.unknown_blob",
+ FT_BYTES, BASE_NONE, NULL, 0,
+ NULL, HFILL }
+ },
{ &hf_iscsi_Padding,
{ "Padding", "iscsi.padding",
- FT_BYTES, BASE_HEX, NULL, 0,
+ FT_BYTES, BASE_NONE, NULL, 0,
"Padding to 4 byte boundary", HFILL }
},
{ &hf_iscsi_ping_data,
{ "PingData", "iscsi.pingdata",
- FT_BYTES, BASE_HEX, NULL, 0,
+ FT_BYTES, BASE_NONE, NULL, 0,
"Ping Data", HFILL }
},
{ &hf_iscsi_immediate_data,
{ "ImmediateData", "iscsi.immediatedata",
- FT_BYTES, BASE_HEX, NULL, 0,
+ FT_BYTES, BASE_NONE, NULL, 0,
"Immediate Data", HFILL }
},
{ &hf_iscsi_write_data,
{ "WriteData", "iscsi.writedata",
- FT_BYTES, BASE_HEX, NULL, 0,
+ FT_BYTES, BASE_NONE, NULL, 0,
"Write Data", HFILL }
},
{ &hf_iscsi_read_data,
{ "ReadData", "iscsi.readdata",
- FT_BYTES, BASE_HEX, NULL, 0,
+ FT_BYTES, BASE_NONE, NULL, 0,
"Read Data", HFILL }
},
{ &hf_iscsi_error_pdu_data,
{ "ErrorPDUData", "iscsi.errorpdudata",
- FT_BYTES, BASE_HEX, NULL, 0,
+ FT_BYTES, BASE_NONE, NULL, 0,
"Error PDU Data", HFILL }
},
- { &hf_iscsi_async_message_data,
- { "AsyncMessageData", "iscsi.asyncmessagedata",
- FT_BYTES, BASE_HEX, NULL, 0,
- "Async Message Data", HFILL }
+ { &hf_iscsi_async_event_data,
+ { "AsyncEventData", "iscsi.asynceventdata",
+ FT_BYTES, BASE_NONE, NULL, 0,
+ "Async Event Data", HFILL }
},
{ &hf_iscsi_vendor_specific_data,
{ "VendorSpecificData", "iscsi.vendorspecificdata",
- FT_BYTES, BASE_HEX, NULL, 0,
+ FT_BYTES, BASE_NONE, NULL, 0,
"Vendor Specific Data", HFILL }
},
{ &hf_iscsi_HeaderDigest32,
},
{ &hf_iscsi_DataDigest,
{ "DataDigest", "iscsi.datadigest",
- FT_BYTES, BASE_HEX, NULL, 0,
+ FT_BYTES, BASE_NONE, NULL, 0,
"Data Digest", HFILL }
},
{ &hf_iscsi_DataDigest32,
{ &hf_iscsi_Opcode,
{ "Opcode", "iscsi.opcode",
FT_UINT8, BASE_HEX, VALS(iscsi_opcodes), 0,
- "Opcode", HFILL }
+ NULL, HFILL }
},
/* #ifdef DRAFT08 */
{ &hf_iscsi_X,
},
{ &hf_iscsi_LUN,
{ "LUN", "iscsi.lun",
- FT_BYTES, BASE_HEX, NULL, 0,
+ FT_BYTES, BASE_NONE, NULL, 0,
"Logical Unit Number", HFILL }
},
{ &hf_iscsi_InitiatorTaskTag,
/* #else */
{ &hf_iscsi_ISID,
{ "ISID", "iscsi.isid",
- FT_BYTES, BASE_HEX, NULL, 0,
+ FT_BYTES, BASE_NONE, NULL, 0,
"Initiator part of session identifier", HFILL }
},
/* #ifdef DRAFT09 */
},
{ &hf_iscsi_KeyValue,
{ "KeyValue", "iscsi.keyvalue",
- FT_STRING, 0, NULL, 0,
+ FT_STRING, BASE_NONE, NULL, 0,
"Key/value pair", HFILL }
},
{ &hf_iscsi_Text_F,
{ &hf_iscsi_TaskManagementFunction_Response,
{ "Response", "iscsi.taskmanfun.response",
FT_UINT8, BASE_HEX, VALS(iscsi_task_management_responses), 0,
- "Response", HFILL }
+ NULL, HFILL }
},
{ &hf_iscsi_TaskManagementFunction_ReferencedTaskTag,
{ "ReferencedTaskTag", "iscsi.taskmanfun.referencedtasktag",
{ &hf_iscsi_Time2Wait,
{ "Time2Wait", "iscsi.time2wait",
FT_UINT16, BASE_HEX, NULL, 0,
- "Time2Wait", HFILL }
+ NULL, HFILL }
},
{ &hf_iscsi_Time2Retain,
{ "Time2Retain", "iscsi.time2retain",
FT_UINT16, BASE_HEX, NULL, 0,
- "Time2Retain", HFILL }
+ NULL, HFILL }
},
{ &hf_iscsi_DesiredDataLength,
{ "DesiredDataLength", "iscsi.desireddatalength",
* subtrees used */
proto_register_field_array(proto_iscsi, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
- register_init_routine (&iscsi_init_protocol);
{
module_t *iscsi_module = prefs_register_protocol(proto_iscsi, NULL);
void
proto_reg_handoff_iscsi(void)
{
- dissector_handle_t iscsi_handle;
-
heur_dissector_add("tcp", dissect_iscsi_heur, proto_iscsi);
- iscsi_handle = create_dissector_handle(dissect_iscsi_handle, proto_iscsi);
+ iscsi_handle = new_create_dissector_handle(dissect_iscsi_handle, proto_iscsi);
dissector_add_handle("tcp.port", iscsi_handle);
}