aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorguy <guy@f5534014-38df-0310-8fa8-9805f1628bb7>2004-05-11 11:27:20 +0000
committerguy <guy@f5534014-38df-0310-8fa8-9805f1628bb7>2004-05-11 11:27:20 +0000
commit311d947d8bd7724bca577ae3333c9b3df0a2fd6a (patch)
tree5bdb291de8f395ab3a8dd31fa749ed479683e21d
parent9434a471e59b72e8bfac33670183fb6dc2bb5e65 (diff)
From metatech:
- Reassembly of MQ messages spanning several PDU - RESET message git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@10854 f5534014-38df-0310-8fa8-9805f1628bb7
-rw-r--r--packet-mq.c207
1 files changed, 172 insertions, 35 deletions
diff --git a/packet-mq.c b/packet-mq.c
index 983b1f2a5c..ac5be3b2bf 100644
--- a/packet-mq.c
+++ b/packet-mq.c
@@ -3,7 +3,7 @@
*
* metatech <metatech@flashmail.com>
*
- * $Id: packet-mq.c,v 1.5 2004/05/01 21:18:09 guy Exp $
+ * $Id: packet-mq.c,v 1.6 2004/05/11 11:27:20 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -62,7 +62,6 @@
* - Find the semantics of the unknown fields
* - Display EBCDIC strings as ASCII
* - Packets which structures built on different platforms
-* - Reassembly of MQ segments
*/
#ifdef HAVE_CONFIG_H
@@ -72,6 +71,7 @@
#include <glib.h>
#include <epan/packet.h>
#include <epan/conversation.h>
+#include "reassemble.h"
#include "prefs.h"
#include "packet-tcp.h"
#include "packet-mq.h"
@@ -184,8 +184,11 @@ static int hf_mq_put_length = -1;
static int hf_mq_open_options = -1;
static int hf_mq_ping_length = -1;
static int hf_mq_ping_buffer = -1;
+static int hf_mq_reset_length = -1;
+static int hf_mq_reset_seqnum = -1;
static int hf_mq_status_length = -1;
static int hf_mq_status_code = -1;
+static int hf_mq_status_value = -1;
static int hf_mq_od_structid = -1;
static int hf_mq_od_version = -1;
static int hf_mq_od_objecttype = -1;
@@ -336,6 +339,7 @@ static gint ett_mq_spi_options = -1;
static gint ett_mq_put = -1;
static gint ett_mq_open = -1;
static gint ett_mq_ping = -1;
+static gint ett_mq_reset = -1;
static gint ett_mq_status = -1;
static gint ett_mq_od = -1;
static gint ett_mq_or = -1;
@@ -360,6 +364,11 @@ static dissector_handle_t data_handle;
static heur_dissector_list_t mq_heur_subdissector_list;
static gboolean mq_desegment = TRUE;
+static gboolean mq_reassembly = FALSE;
+
+static GHashTable *mq_fragment_table = NULL;
+static GHashTable *mq_reassembled_table = NULL;
+
#define MQ_PORT_TCP 1414
#define MQ_SOCKET_SPX 0x5E86
@@ -555,7 +564,6 @@ static gboolean mq_desegment = TRUE;
#define MQ_XA_RBPROTO 105
#define MQ_XA_RBTIMEOUT 106
#define MQ_XA_RBTRANSIENT 107
-#define MQ_XA_RBEND 107
#define MQ_XA_NOMIGRATE 9
#define MQ_XA_HEURHAZ 8
#define MQ_XA_HEURCOM 7
@@ -603,6 +611,7 @@ static gboolean mq_desegment = TRUE;
#define MQ_TEXT_PUT "MQPUT/MQGET"
#define MQ_TEXT_OPEN "MQOPEN/MQCLOSE"
#define MQ_TEXT_PING "PING"
+#define MQ_TEXT_RESET "RESET"
#define MQ_TEXT_STAT "STATUS"
#define MQ_TEXT_SPI "SPI"
#define MQ_TEXT_XA "XA"
@@ -729,7 +738,6 @@ static const value_string mq_xaer_vals[] = {
{ MQ_XA_RBPROTO, "XA_RBPROTO" },
{ MQ_XA_RBTIMEOUT, "XA_RBTIMEOUT" },
{ MQ_XA_RBTRANSIENT, "XA_RBTRANSIENT" },
- { MQ_XA_RBEND, "XA_RBEND" },
{ MQ_XA_NOMIGRATE, "XA_NOMIGRATE" },
{ MQ_XA_HEURHAZ, "XA_HEURHAZ" },
{ MQ_XA_HEURCOM, "XA_HEURCOM" },
@@ -838,7 +846,6 @@ static gint
dissect_mq_md(tvbuff_t *tvb, proto_tree *tree, gboolean bLittleEndian, gint offset, struct mq_msg_properties* tMsgProps)
{
proto_tree *mq_tree = NULL;
- proto_item *ti = NULL;
guint32 structId;
gint iSizeMD = 0;
@@ -863,6 +870,7 @@ dissect_mq_md(tvbuff_t *tvb, proto_tree *tree, gboolean bLittleEndian, gint offs
tMsgProps->iOffsetFormat = offset + 32;
if (tree)
{
+ proto_item *ti = NULL;
ti = proto_tree_add_text(tree, tvb, offset, iSizeMD, MQ_TEXT_MD);
mq_tree = proto_item_add_subtree(ti, ett_mq_md);
@@ -1363,22 +1371,30 @@ dissect_mq_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
/* Some status are 28 bytes long and some are 36 bytes long */
guint32 iStatus = 0;
+ gint iStatusLength = 0;
iStatus = tvb_get_guint32_endian(tvb, offset + 4, bLittleEndian);
+ iStatusLength = tvb_get_guint32_endian(tvb, offset, bLittleEndian);
- if (check_col(pinfo->cinfo, COL_INFO))
- {
- if (iStatus != 0)
- col_append_fstr(pinfo->cinfo, COL_INFO, ": Code=%s", val_to_str(iStatus, mq_status_vals, "Unknown (0x%08x)"));
- }
- if (tree)
+ if (tvb_length_remaining(tvb, offset) >= iStatusLength)
{
- ti = proto_tree_add_text(mqroot_tree, tvb, offset, 8, MQ_TEXT_STAT);
- mq_tree = proto_item_add_subtree(ti, ett_mq_status);
-
- proto_tree_add_item(mq_tree, hf_mq_status_length, tvb, offset, 4, bLittleEndian);
- proto_tree_add_item(mq_tree, hf_mq_status_code, tvb, offset + 4, 4, bLittleEndian);
+ if (check_col(pinfo->cinfo, COL_INFO))
+ {
+ if (iStatus != 0)
+ col_append_fstr(pinfo->cinfo, COL_INFO, ": Code=%s", val_to_str(iStatus, mq_status_vals, "Unknown (0x%08x)"));
+ }
+ if (tree)
+ {
+ ti = proto_tree_add_text(mqroot_tree, tvb, offset, 8, MQ_TEXT_STAT);
+ mq_tree = proto_item_add_subtree(ti, ett_mq_status);
+
+ proto_tree_add_item(mq_tree, hf_mq_status_length, tvb, offset, 4, bLittleEndian);
+ proto_tree_add_item(mq_tree, hf_mq_status_code, tvb, offset + 4, 4, bLittleEndian);
+
+ if (iStatusLength >= 12)
+ proto_tree_add_item(mq_tree, hf_mq_status_value, tvb, offset + 8, 4, bLittleEndian);
+ }
+ offset += iStatusLength;
}
- offset += 8;
}
else if (opcode == MQ_TST_PING && tvb_length_remaining(tvb, offset) > 4)
{
@@ -1392,6 +1408,18 @@ dissect_mq_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
}
offset = tvb_length(tvb);
}
+ else if (opcode == MQ_TST_RESET && tvb_length_remaining(tvb, offset) >= 8)
+ {
+ if (tree)
+ {
+ ti = proto_tree_add_text(mqroot_tree, tvb, offset, -1, MQ_TEXT_RESET);
+ mq_tree = proto_item_add_subtree(ti, ett_mq_reset);
+
+ proto_tree_add_item(mq_tree, hf_mq_reset_length, tvb, offset, 4, bLittleEndian);
+ proto_tree_add_item(mq_tree, hf_mq_reset_seqnum, tvb, offset + 4, 4, bLittleEndian);
+ }
+ offset = tvb_length(tvb);
+ }
else if (opcode == MQ_TST_MQCONN && tvb_length_remaining(tvb, offset) > 0)
{
gint iSizeCONN = 0;
@@ -2238,6 +2266,7 @@ dissect_mq_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
/* Call subdissector for the payload */
tvbuff_t* next_tvb = NULL;
struct mqinfo mqinfo;
+ /* Format, encoding and character set are "data type" information, not subprotocol information */
mqinfo.encoding = tvb_get_guint32_endian(tvb, tMsgProps.iOffsetEncoding, bLittleEndian);
mqinfo.ccsid = tvb_get_guint32_endian(tvb, tMsgProps.iOffsetCcsid, bLittleEndian);
tvb_memcpy(tvb, mqinfo.format, tMsgProps.iOffsetFormat, 8);
@@ -2261,8 +2290,8 @@ dissect_mq_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
}
else
{
- /* This is a MQ segment continuation (no PDU reassembly is done) */
- if (check_col(pinfo->cinfo, COL_INFO)) col_append_str(pinfo->cinfo, COL_INFO, " [Segment Continuation]");
+ /* This is a MQ segment continuation (if MQ reassembly is not enabled) */
+ if (check_col(pinfo->cinfo, COL_INFO)) col_append_str(pinfo->cinfo, COL_INFO, " [Unreassembled MQ]");
call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
}
}
@@ -2270,7 +2299,7 @@ dissect_mq_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
else
{
/* This packet is a TCP continuation of a segment (if desegmentation is not enabled) */
- if (check_col(pinfo->cinfo, COL_INFO)) col_append_str(pinfo->cinfo, COL_INFO, "Continuation");
+ if (check_col(pinfo->cinfo, COL_INFO)) col_append_str(pinfo->cinfo, COL_INFO, " [Undesegmented]");
if (tree)
{
proto_tree_add_item(tree, proto_mq, tvb, offset, -1, FALSE);
@@ -2280,6 +2309,91 @@ dissect_mq_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
}
}
+
+static void
+reassemble_mq(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ /* Reassembly of the MQ messages that span several PDU (several TSH) */
+ /* Typically a TCP PDU is 1460 bytes and a MQ PDU is 32766 bytes */
+ if (tvb_length(tvb) >= 28)
+ {
+ guint32 structId;
+ structId = tvb_get_ntohl(tvb, 0);
+
+ if (structId == MQ_STRUCTID_TSH || structId == MQ_STRUCTID_TSH_EBCDIC)
+ {
+ guint8 iControlFlags = 0;
+ guint32 iSegmentLength = 0;
+ guint32 iBeginLength = 0;
+ guint8 opcode;
+ gboolean bFirstSegment;
+ gboolean bLastSegment;
+ opcode = tvb_get_guint8(tvb, 9);
+ iControlFlags = tvb_get_guint8(tvb, 10);
+ iSegmentLength = tvb_get_ntohl(tvb, 4);
+ bFirstSegment = ((iControlFlags & MQ_TCF_FIRST) != 0);
+ bLastSegment = ((iControlFlags & MQ_TCF_LAST) != 0);
+
+ if (opcode > 0x80 && !(bFirstSegment && bLastSegment))
+ {
+ /* Optimisation : only fragmented segments go through the reassembly process */
+ if (mq_reassembly)
+ {
+ tvbuff_t* next_tvb;
+ fragment_data* fd_head;
+ guint32 iConnectionId = (pinfo->srcport + pinfo->destport);
+ if (opcode > 0x80 && !bFirstSegment) iBeginLength = 28;
+ fd_head = fragment_add_seq_next(tvb, iBeginLength, pinfo, iConnectionId, mq_fragment_table, mq_reassembled_table, iSegmentLength - iBeginLength, !bLastSegment);
+ if (fd_head != NULL && pinfo->fd->num == fd_head->reassembled_in)
+ {
+ /* Reassembly finished */
+ if (fd_head->next != NULL)
+ {
+ /* 2 or more fragments */
+ next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
+ tvb_set_child_real_data_tvbuff(tvb, next_tvb);
+ add_new_data_source(pinfo, next_tvb, "Reassembled MQ");
+ }
+ else
+ {
+ /* Only 1 fragment */
+ next_tvb = tvb;
+ }
+ dissect_mq_pdu(next_tvb, pinfo, tree);
+ return;
+ }
+ else
+ {
+ /* Reassembly in progress */
+ if (check_col(pinfo->cinfo, COL_PROTOCOL)) col_set_str(pinfo->cinfo, COL_PROTOCOL, "MQ");
+ if (check_col(pinfo->cinfo, COL_INFO)) col_add_fstr(pinfo->cinfo, COL_INFO, "%s [Reassembled MQ]", val_to_str(opcode, mq_opcode_vals, "Unknown (0x%02x)"));
+ if (tree)
+ {
+ proto_item* ti = NULL;
+ ti = proto_tree_add_item(tree, proto_mq, tvb, 0, -1, FALSE);
+ proto_item_append_text(ti, " (%s) [Reassembled MQ]", val_to_str(opcode, mq_opcode_vals, "Unknown (0x%02x)"));
+ }
+ return;
+ }
+ }
+ else
+ {
+ dissect_mq_pdu(tvb, pinfo, tree);
+ if (bFirstSegment)
+ {
+ /* MQ segment is the first of a unreassembled series */
+ if (check_col(pinfo->cinfo, COL_INFO)) col_append_str(pinfo->cinfo, COL_INFO, " [Unreassembled MQ]");
+ }
+ return;
+ }
+ }
+ /* Reassembly not enabled or non-fragmented message */
+ dissect_mq_pdu(tvb, pinfo, tree);
+ return;
+ }
+ }
+}
+
static guint
get_mq_pdu_len(tvbuff_t *tvb, int offset)
{
@@ -2294,12 +2408,13 @@ get_mq_pdu_len(tvbuff_t *tvb, int offset)
static void
dissect_mq_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
- tcp_dissect_pdus(tvb, pinfo, tree, mq_desegment, 28, get_mq_pdu_len, dissect_mq_pdu);
+ tcp_dissect_pdus(tvb, pinfo, tree, mq_desegment, 28, get_mq_pdu_len, reassemble_mq);
}
static void
dissect_mq_spx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
+ /* Since SPX has no standard desegmentation, MQ cannot be performed as well */
dissect_mq_pdu(tvb, pinfo, tree);
}
@@ -2326,7 +2441,7 @@ dissect_mq_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint iProto
if (iProto == MQ_XPT_TCP) conversation_set_dissector(conversation, mq_tcp_handle);
/* Dissect the packet */
- dissect_mq_pdu(tvb, pinfo, tree);
+ reassemble_mq(tvb, pinfo, tree);
return TRUE;
}
}
@@ -2351,6 +2466,13 @@ dissect_mq_heur_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
return dissect_mq_heur(tvb, pinfo, tree, MQ_XPT_HTTP);
}
+static void
+mq_init(void)
+{
+ fragment_table_init(&mq_fragment_table);
+ reassembled_table_init(&mq_reassembled_table);
+}
+
void
proto_register_mq(void)
{
@@ -2385,18 +2507,6 @@ proto_register_mq(void)
{ &hf_mq_tsh_padding,
{ "Padding", "mq.tsh.padding", FT_UINT16, BASE_HEX, NULL, 0x0, "TSH Padding", HFILL }},
- { &hf_mq_api_replylength,
- { "Reply length", "mq.tsh.replylength", FT_UINT32, BASE_DEC, NULL, 0x0, "API Reply length", HFILL }},
-
- { &hf_mq_api_completioncode,
- { "Completion code", "mq.tsh.completioncode", FT_UINT32, BASE_DEC, NULL, 0x0, "API Completion code", HFILL }},
-
- { &hf_mq_api_reasoncode,
- { "Reason code", "mq.tsh.reasoncode", FT_UINT32, BASE_DEC, NULL, 0x0, "API Reason code", HFILL }},
-
- { &hf_mq_api_objecthandle,
- { "Object handle", "mq.tsh.hobj", FT_UINT32, BASE_HEX, NULL, 0x0, "API Object handle", HFILL }},
-
{ &hf_mq_tsh_tcf_confirmreq,
{ "Confirm request", "mq.tsh.tcf.confirmreq", FT_BOOLEAN, 8, TFS(&flags_set_truth), MQ_TCF_CONFIRM_REQUEST, "TSH TCF Confirm request", HFILL }},
@@ -2421,6 +2531,18 @@ proto_register_mq(void)
{ &hf_mq_tsh_tcf_dlq,
{ "DLQ used", "mq.tsh.tcf.dlq", FT_BOOLEAN, 8, TFS(&flags_set_truth), MQ_TCF_DLQ_USED, "TSH TCF DLQ used", HFILL }},
+ { &hf_mq_api_replylength,
+ { "Reply length", "mq.api.replylength", FT_UINT32, BASE_DEC, NULL, 0x0, "API Reply length", HFILL }},
+
+ { &hf_mq_api_completioncode,
+ { "Completion code", "mq.api.completioncode", FT_UINT32, BASE_DEC, NULL, 0x0, "API Completion code", HFILL }},
+
+ { &hf_mq_api_reasoncode,
+ { "Reason code", "mq.api.reasoncode", FT_UINT32, BASE_DEC, NULL, 0x0, "API Reason code", HFILL }},
+
+ { &hf_mq_api_objecthandle,
+ { "Object handle", "mq.api.hobj", FT_UINT32, BASE_HEX, NULL, 0x0, "API Object handle", HFILL }},
+
{ &hf_mq_id_icf_msgseq,
{ "Message sequence", "mq.id.icf.msgseq", FT_BOOLEAN, 8, TFS(&flags_set_truth), MQ_ICF_MSG_SEQ, "ID ICF Message sequence", HFILL }},
@@ -2676,12 +2798,21 @@ proto_register_mq(void)
{ &hf_mq_ping_buffer,
{ "Buffer", "mq.ping.buffer", FT_BYTES, BASE_DEC, NULL, 0x0, "PING buffer", HFILL }},
+ { &hf_mq_reset_length,
+ { "Length", "mq.ping.length", FT_UINT32, BASE_DEC, NULL, 0x0, "RESET length", HFILL }},
+
+ { &hf_mq_reset_seqnum,
+ { "Sequence number", "mq.ping.seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, "RESET sequence number", HFILL }},
+
{ &hf_mq_status_length,
{ "Length", "mq.status.length", FT_UINT32, BASE_DEC, NULL, 0x0, "STATUS length", HFILL }},
{ &hf_mq_status_code,
{ "Code", "mq.status.code", FT_UINT32, BASE_DEC, VALS(mq_status_vals), 0x0, "STATUS code", HFILL }},
+ { &hf_mq_status_value,
+ { "Value", "mq.status.value", FT_UINT32, BASE_DEC, NULL, 0x0, "STATUS value", HFILL }},
+
{ &hf_mq_od_structid,
{ "OD structid", "mq.od.structid", FT_STRINGZ, BASE_HEX, NULL, 0x0, "OD structid", HFILL }},
@@ -3095,6 +3226,7 @@ proto_register_mq(void)
&ett_mq_put,
&ett_mq_open,
&ett_mq_ping,
+ &ett_mq_reset,
&ett_mq_status,
&ett_mq_od,
&ett_mq_or,
@@ -3120,12 +3252,17 @@ proto_register_mq(void)
proto_register_subtree_array(ett, array_length(ett));
register_heur_dissector_list("mq", &mq_heur_subdissector_list);
+ register_init_routine(mq_init);
mq_module = prefs_register_protocol(proto_mq, NULL);
- prefs_register_bool_preference(mq_module, "reassembly", /*"desegment",*/
+ prefs_register_bool_preference(mq_module, "desegment",
"Desegment all MQ messages spanning multiple TCP segments",
"Whether the MQ dissector should desegment all messages spanning multiple TCP segments",
&mq_desegment);
+ prefs_register_bool_preference(mq_module, "reassembly",
+ "Reassemble segmented MQ messages",
+ "Whether the MQ dissector should reassemble all MQ messages spanning multiple TSH segments",
+ &mq_reassembly);
}
void