* Routines for iSCSI dissection
* Copyright 2001, Eurologic and Mark Burton <markb@ordern.com>
*
- * $Id: packet-iscsi.c,v 1.44 2003/06/15 00:16:06 sahlberg Exp $
+ * $Id: packet-iscsi.c,v 1.47 2003/09/09 09:54:13 sahlberg Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
#include "prefs.h"
#include <epan/conversation.h>
#include "packet-scsi.h"
+#include "epan/nstime.h"
/* the absolute values of these constants don't matter as long as
* latter revisions of the protocol are assigned a larger number */
/* Initialize the protocol and registered fields */
static int proto_iscsi = -1;
+static int hf_iscsi_time = -1;
+static int hf_iscsi_request_frame = -1;
+static int hf_iscsi_data_in_frame = -1;
+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_Padding = -1;
static int hf_iscsi_ping_data = -1;
static gint ett_iscsi_ISID = -1;
/* #endif */
-typedef struct _iscsi_conv_key {
- guint32 conv_idx;
- guint32 itt;
-} iscsi_conv_key_t;
-
-typedef struct _iscsi_conv_data {
- guint32 iscsi_dl;
- guint32 abs_secs;
- guint32 abs_usecs;
-} iscsi_conv_data_t;
-
-static GHashTable *iscsi_req_hash = NULL;
-static GMemChunk *iscsi_req_keys = NULL;
-static GMemChunk *iscsi_req_vals = NULL;
-static guint32 iscsi_init_count = 25;
/* #ifdef DRAFT08 */
#define X_BIT 0x80
return CRC32C_SWAP(crc);
}
-/*
- * Hash Functions
+
+
+
+
+/* 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;
+} 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(gconstpointer v, gconstpointer w)
+iscsi_equal_unmatched(gconstpointer v, gconstpointer w)
{
- const iscsi_conv_key_t *v1 = (const iscsi_conv_key_t *)v;
- const iscsi_conv_key_t *v2 = (const iscsi_conv_key_t *)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);
+ return (v1->conv_idx == v2->conv_idx)&&(v1->itt == v2->itt);
}
static guint
-iscsi_hash (gconstpointer v)
+iscsi_hash_unmatched (gconstpointer v)
{
- const iscsi_conv_key_t *key = (const iscsi_conv_key_t *)v;
+ const iscsi_conv_data_t *key = (const iscsi_conv_data_t *)v;
guint val;
- val = key->conv_idx;
+ 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_req_keys)
- g_mem_chunk_destroy(iscsi_req_keys);
if (iscsi_req_vals)
g_mem_chunk_destroy(iscsi_req_vals);
- if (iscsi_req_hash)
- g_hash_table_destroy(iscsi_req_hash);
+ if (iscsi_req_unmatched)
+ g_hash_table_destroy(iscsi_req_unmatched);
+ if (iscsi_req_matched)
+ g_hash_table_destroy(iscsi_req_matched);
- iscsi_req_hash = g_hash_table_new(iscsi_hash, iscsi_equal);
- iscsi_req_keys = g_mem_chunk_new("iscsi_req_keys",
- sizeof(iscsi_conv_key_t),
- iscsi_init_count * sizeof(iscsi_conv_key_t),
- G_ALLOC_AND_FREE);
+ 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_req_vals = g_mem_chunk_new("iscsi_req_vals",
sizeof(iscsi_conv_data_t),
iscsi_init_count * sizeof(iscsi_conv_data_t),
guint8 scsi_status = 0;
guint cdb_offset = offset + 32; /* offset of CDB from start of PDU */
guint end_offset = offset + tvb_length_remaining(tvb, offset);
- guint32 del_usecs = 0;
conversation_t *conversation = NULL;
iscsi_conv_data_t *cdata = NULL;
- iscsi_conv_key_t ckey, *req_key;
scsi_task_id_t task_key;
int paddedDataSegmentLength = data_segment_len;
if(paddedDataSegmentLength & 3)
pinfo->ptype, pinfo->srcport,
pinfo->destport, 0);
if (conversation) {
- ckey.conv_idx = conversation->index;
- ckey.itt = tvb_get_ntohl (tvb, offset+16);
-
- cdata = (iscsi_conv_data_t *)g_hash_table_lookup (iscsi_req_hash,
- &ckey);
+ if (!pinfo->fd->flags.visited){
+ iscsi_conv_data_t ckey;
+ ckey.conv_idx = conversation->index;
+ 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:
+ 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 = conversation->index;
+ 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;
+ }
+
+ /* 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);
+ }
- task_key.conv_id = ckey.conv_idx;
- task_key.task_id = ckey.itt;
- pinfo->private_data = &task_key;
+ 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;
+ }
} else {
/* no conversation, meaning we didn't see the request */
pinfo->private_data = NULL;
}
- if (cdata) {
- del_usecs = (pinfo->fd->abs_secs - cdata->abs_secs)* 1000000 +
- (pinfo->fd->abs_usecs - cdata->abs_usecs);
- }
- }
- else if (opcode == ISCSI_OPCODE_SCSI_COMMAND) {
+ } else if (opcode == ISCSI_OPCODE_SCSI_COMMAND) {
conversation = find_conversation (&pinfo->src, &pinfo->dst,
pinfo->ptype, pinfo->srcport,
pinfo->destport, 0);
pinfo->destport, 0);
}
- ckey.conv_idx = conversation->index;
- ckey.itt = tvb_get_ntohl (tvb, offset+16);
-
- cdata = (iscsi_conv_data_t *)g_hash_table_lookup (iscsi_req_hash,
- &ckey);
- if (cdata) {
- /* Since we never free the memory used by an exchange, this maybe a
- * case of another request using the same exchange as a previous
- * req.
- */
- cdata->abs_usecs = pinfo->fd->abs_usecs;
- cdata->abs_secs = pinfo->fd->abs_secs;
- }
- else {
- req_key = g_mem_chunk_alloc (iscsi_req_keys);
- req_key->conv_idx = conversation->index;
- req_key->itt = tvb_get_ntohl (tvb, offset+16);
+ if (!pinfo->fd->flags.visited){
+ iscsi_conv_data_t ckey;
- cdata = g_mem_chunk_alloc (iscsi_req_vals);
- cdata->abs_usecs = pinfo->fd->abs_usecs;
- cdata->abs_secs = pinfo->fd->abs_secs;
+ /* first time we see this packet. */
+ /*check if we have seen this request before and delete it in that case */
+ ckey.conv_idx = conversation->index;
+ 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);
+ }
- g_hash_table_insert (iscsi_req_hash, req_key, cdata);
+ /* add this new transaction to teh unmatched table */
+ cdata = g_mem_chunk_alloc (iscsi_req_vals);
+ cdata->conv_idx = conversation->index;
+ 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);
+ } else {
+ iscsi_conv_data_t ckey;
+ ckey.conv_idx = conversation->index;
+ 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);
}
- /* The SCSI protocol uses this as the key to detect a
- * SCSI-level conversation. */
- task_key.conv_id = ckey.conv_idx;
- task_key.task_id = ckey.itt;
- pinfo->private_data = &task_key;
+
+ 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;
+ }
}
else {
pinfo->private_data = NULL;
offset, -1, "iSCSI (%s)",
opcode_str);
ti = proto_item_add_subtree(tp, ett_iscsi);
-
- proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb,
+ }
+ proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb,
offset + 0, 1, opcode);
- if((opcode & TARGET_OPCODE_BIT) == 0) {
+ if((opcode & TARGET_OPCODE_BIT) == 0) {
/* initiator -> target */
gint b = tvb_get_guint8(tvb, offset + 0);
- if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
+ if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
if(opcode != ISCSI_OPCODE_SCSI_DATA_OUT &&
opcode != ISCSI_OPCODE_LOGOUT_COMMAND &&
opcode != ISCSI_OPCODE_SNACK_REQUEST)
proto_tree_add_boolean(ti, hf_iscsi_X, tvb, offset + 0, 1, b);
- }
+ }
if(opcode != ISCSI_OPCODE_SCSI_DATA_OUT &&
opcode != ISCSI_OPCODE_LOGIN_COMMAND &&
opcode != ISCSI_OPCODE_SNACK_REQUEST)
proto_tree_add_boolean(ti, hf_iscsi_I, tvb, offset + 0, 1, b);
- }
+ }
+
+ /* 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 (cdata->request_frame)
+ proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->request_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;
+ 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(opcode == ISCSI_OPCODE_NOP_OUT) {
+ if(opcode == ISCSI_OPCODE_NOP_OUT) {
/* NOP Out */
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_ExpStatSN, tvb, offset + 28, 4, FALSE);
offset = handleHeaderDigest(ti, tvb, offset, 48);
offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_ping_data);
- }
- else if(opcode == ISCSI_OPCODE_NOP_IN) {
+ } else if(opcode == ISCSI_OPCODE_NOP_IN) {
/* NOP In */
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);
offset = handleHeaderDigest(ti, tvb, offset, 48);
offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_ping_data);
- }
- else if(opcode == ISCSI_OPCODE_SCSI_COMMAND) {
+ } else if(opcode == ISCSI_OPCODE_SCSI_COMMAND) {
/* SCSI Command */
guint32 ahsLen = tvb_get_guint8(tvb, offset + 4) * 4;
{
offset = handleHeaderDigest(ti, tvb, offset, 48 + ahsLen);
}
offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_immediate_data);
- }
- else if(opcode == ISCSI_OPCODE_SCSI_RESPONSE) {
+ } else if(opcode == ISCSI_OPCODE_SCSI_RESPONSE) {
/* SCSI Response */
- if (del_usecs) {
- if (del_usecs > 1000)
- proto_tree_add_text (ti, tvb, offset, 0,
- "Cmd Response Time: %d msecs",
- del_usecs/1000);
- else
- proto_tree_add_text (ti, tvb, offset, 0,
- "Cmd Response Time: %d usecs",
- del_usecs);
- }
{
gint b = tvb_get_guint8(tvb, offset + 1);
proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
/* do not update offset here because the data segment is
* dissected below */
handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
- }
- else if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION) {
+ } else if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION) {
/* Task Management Function */
proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_Function, tvb, offset + 1, 1, FALSE);
if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_RefCmdSN, tvb, offset + 32, 4, FALSE);
offset = handleHeaderDigest(ti, tvb, offset, 48);
- }
- else if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE) {
+ } else if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE) {
/* Task Management Function Response */
proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_Response, tvb, offset + 2, 1, FALSE);
if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
offset = handleHeaderDigest(ti, tvb, offset, 48);
- }
- else if(opcode == ISCSI_OPCODE_LOGIN_COMMAND) {
+ } else if(opcode == ISCSI_OPCODE_LOGIN_COMMAND) {
/* Login Command */
int digestsActive = 0;
{
proto_tree_add_boolean(ti, hf_iscsi_Login_X, tvb, offset + 1, 1, b);
}
proto_tree_add_item(ti, hf_iscsi_Login_CSG, tvb, offset + 1, 1, FALSE);
- proto_tree_add_item(ti, hf_iscsi_Login_NSG, tvb, offset + 1, 1, FALSE);
+
+ /* NSG is undefined unless T is set */
+ if(b&0x80){
+ proto_tree_add_item(ti, hf_iscsi_Login_NSG, tvb, offset + 1, 1, FALSE);
+ }
}
proto_tree_add_item(ti, hf_iscsi_VersionMax, tvb, offset + 2, 1, FALSE);
proto_tree_add_item(ti, hf_iscsi_VersionMin, tvb, offset + 3, 1, FALSE);
else
offset += 48;
offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, digestsActive);
- }
- else if(opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
+ } else if(opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
/* Login Response */
int digestsActive = 0;
{
proto_tree_add_boolean(ti, hf_iscsi_Login_C, tvb, offset + 1, 1, b);
}
proto_tree_add_item(ti, hf_iscsi_Login_CSG, tvb, offset + 1, 1, FALSE);
- proto_tree_add_item(ti, hf_iscsi_Login_NSG, tvb, offset + 1, 1, FALSE);
+ /* NSG is undefined unless T is set */
+ if(b&0x80){
+ proto_tree_add_item(ti, hf_iscsi_Login_NSG, tvb, offset + 1, 1, FALSE);
+ }
}
proto_tree_add_item(ti, hf_iscsi_VersionMax, tvb, offset + 2, 1, FALSE);
else
offset += 48;
offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, digestsActive);
- }
- else if(opcode == ISCSI_OPCODE_TEXT_COMMAND) {
+ } else if(opcode == ISCSI_OPCODE_TEXT_COMMAND) {
/* Text Command */
{
gint b = tvb_get_guint8(tvb, offset + 1);
proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
offset = handleHeaderDigest(ti, tvb, offset, 48);
offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, TRUE);
- }
- else if(opcode == ISCSI_OPCODE_TEXT_RESPONSE) {
+ } else if(opcode == ISCSI_OPCODE_TEXT_RESPONSE) {
/* Text Response */
{
gint b = tvb_get_guint8(tvb, offset + 1);
proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
offset = handleHeaderDigest(ti, tvb, offset, 48);
offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, TRUE);
- }
- else if(opcode == ISCSI_OPCODE_SCSI_DATA_OUT) {
+ } else if(opcode == ISCSI_OPCODE_SCSI_DATA_OUT) {
/* SCSI Data Out (write) */
{
gint b = tvb_get_guint8(tvb, offset + 1);
/* do not update offset here because the data segment is
* dissected below */
handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
- }
- else if(opcode == ISCSI_OPCODE_SCSI_DATA_IN) {
+ } else if(opcode == ISCSI_OPCODE_SCSI_DATA_IN) {
/* SCSI Data In (read) */
{
gint b = tvb_get_guint8(tvb, offset + 1);
/* do not update offset here because the data segment is
* dissected below */
handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
- }
- else if(opcode == ISCSI_OPCODE_LOGOUT_COMMAND) {
+ } else if(opcode == ISCSI_OPCODE_LOGOUT_COMMAND) {
/* Logout Command */
if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
proto_tree_add_item(ti, hf_iscsi_Logout_Reason, tvb, offset + 1, 1, FALSE);
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);
offset = handleHeaderDigest(ti, tvb, offset, 48);
- }
- else if(opcode == ISCSI_OPCODE_LOGOUT_RESPONSE) {
+ } else if(opcode == ISCSI_OPCODE_LOGOUT_RESPONSE) {
/* Logout Response */
proto_tree_add_item(ti, hf_iscsi_Logout_Response, tvb, offset + 2, 1, FALSE);
if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
proto_tree_add_item(ti, hf_iscsi_Time2Wait, tvb, offset + 40, 2, FALSE);
proto_tree_add_item(ti, hf_iscsi_Time2Retain, tvb, offset + 42, 2, FALSE);
offset = handleHeaderDigest(ti, tvb, offset, 48);
- }
- else if(opcode == ISCSI_OPCODE_SNACK_REQUEST) {
+ } else if(opcode == ISCSI_OPCODE_SNACK_REQUEST) {
/* SNACK Request */
{
gint b = tvb_get_guint8(tvb, offset + 1);
proto_tree_add_item(ti, hf_iscsi_RunLength, tvb, offset + 44, 4, FALSE);
}
offset = handleHeaderDigest(ti, tvb, offset, 48);
- }
- else if(opcode == ISCSI_OPCODE_R2T) {
+ } else if(opcode == ISCSI_OPCODE_R2T) {
/* R2T */
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_BufferOffset, tvb, offset + 40, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_DesiredDataLength, tvb, offset + 44, 4, FALSE);
offset = handleHeaderDigest(ti, tvb, offset, 48);
- }
- else if(opcode == ISCSI_OPCODE_ASYNC_MESSAGE) {
+ } else if(opcode == ISCSI_OPCODE_ASYNC_MESSAGE) {
/* Asynchronous Message */
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_Parameter3, tvb, offset + 42, 2, FALSE);
offset = handleHeaderDigest(ti, tvb, offset, 48);
offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_async_message_data);
- }
- else if(opcode == ISCSI_OPCODE_REJECT) {
+ } else if(opcode == ISCSI_OPCODE_REJECT) {
/* Reject */
proto_tree_add_item(ti, hf_iscsi_Reject_Reason, tvb, offset + 2, 1, FALSE);
if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
offset = handleHeaderDigest(ti, tvb, offset, 48);
offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_error_pdu_data);
- }
- else if(opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_I0 ||
+ } else if(opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_I0 ||
opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_I1 ||
opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_I2 ||
opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_T0 ||
proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
offset = handleHeaderDigest(ti, tvb, offset, 48);
offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_vendor_specific_data);
- }
-
- proto_item_set_len(ti, offset - original_offset);
}
+ proto_item_set_len(ti, offset - original_offset);
+
if((opcode & ((iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08)?
~(X_BIT | I_BIT) :
~I_BIT)) == ISCSI_OPCODE_SCSI_COMMAND) {
else {
dissect_scsi_rsp (tvb, pinfo, tree);
}
- if (cdata && tree) {
- /* destroy the data structures for this SCSI task */
-#if 0
- g_mem_chunk_free (iscsi_req_vals, cdata);
- g_hash_table_remove (iscsi_req_hash, &ckey);
- pinfo->private_data = NULL;
-#endif
- }
}
else if ((opcode == ISCSI_OPCODE_SCSI_DATA_IN) ||
(opcode == ISCSI_OPCODE_SCSI_DATA_OUT)) {
}
static gboolean
-dissect_iscsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
+dissect_iscsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean check_port) {
/* Set up structures needed to add the protocol subtree and manage it */
guint iSCSIPdusDissected = 0;
guint offset = 0;
if(opcode_str == NULL) {
badPdu = TRUE;
}
- else if(iscsi_port != 0 &&
+ else if(check_port && iscsi_port != 0 &&
(((opcode & TARGET_OPCODE_BIT) && pinfo->srcport != iscsi_port) ||
(!(opcode & TARGET_OPCODE_BIT) && pinfo->destport != iscsi_port))) {
badPdu = TRUE;
a PDU.
*/
if(!pinfo->fd->flags.visited){
- if(pduLen>tvb_reported_length_remaining(tvb, offset)){
+ if(pduLen>(guint32)tvb_reported_length_remaining(tvb, offset)){
pinfo->want_pdu_tracking=2;
pinfo->bytes_until_next_pdu=pduLen-tvb_reported_length_remaining(tvb, offset);
}
return iSCSIPdusDissected > 0;
}
+/* This is called for those sessions where we have explicitely said
+ 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.
+*/
+static void
+dissect_iscsi_handle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
+ dissect_iscsi(tvb, pinfo, tree, FALSE);
+}
+
+/* This is called through the heuristic handler.
+ In this case we also want to check that the port matches the preference
+ setting for iSCSI in order to reduce the number of
+ false positives.
+*/
+static gboolean
+dissect_iscsi_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
+ return dissect_iscsi(tvb, pinfo, tree, TRUE);
+}
+
/* Register the protocol with Ethereal */
/* Setup list of header fields See Section 1.6.1 for details*/
static hf_register_info hf[] = {
+ { &hf_iscsi_request_frame,
+ { "Request in", "iscsi.request_frame",
+ FT_FRAMENUM, BASE_NONE, NULL, 0,
+ "The request to this transaction is in this frame", HFILL }},
+
+ { &hf_iscsi_time,
+ { "Time from request", "iscsi.time",
+ FT_RELATIVE_TIME, BASE_NONE, NULL, 0,
+ "Time between the Command and the Response", HFILL }},
+
+ { &hf_iscsi_data_in_frame,
+ { "Data In in", "iscsi.data_in_frame",
+ FT_FRAMENUM, BASE_NONE, NULL, 0,
+ "The Data In for this transaction is in this frame", HFILL }},
+
+ { &hf_iscsi_data_out_frame,
+ { "Data Out in", "iscsi.data_out_frame",
+ FT_FRAMENUM, BASE_NONE, NULL, 0,
+ "The Data Out for this transaction is in this frame", HFILL }},
+
+ { &hf_iscsi_response_frame,
+ { "Response in", "iscsi.response_frame",
+ FT_FRAMENUM, BASE_NONE, NULL, 0,
+ "The response to this transaction is in this frame", HFILL }},
+
{ &hf_iscsi_AHS,
{ "AHS", "iscsi.ahs",
FT_BYTES, BASE_HEX, NULL, 0,
10,
&bogus_pdu_data_length_threshold);
+
prefs_register_uint_preference(iscsi_module,
"target_port",
"Target port",
void
proto_reg_handoff_iscsi(void)
{
- heur_dissector_add("tcp", dissect_iscsi, proto_iscsi);
+ dissector_handle_t iscsi_handle;
+
+ heur_dissector_add("tcp", dissect_iscsi_heur, proto_iscsi);
+
+ iscsi_handle = create_dissector_handle(dissect_iscsi_handle, proto_iscsi);
+ dissector_add_handle("tcp.port", iscsi_handle);
}