aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRonnie Sahlberg <ronnie_sahlberg@ozemail.com.au>2003-03-06 09:01:47 +0000
committerRonnie Sahlberg <ronnie_sahlberg@ozemail.com.au>2003-03-06 09:01:47 +0000
commite00fb8c41365618d603fb0c8943540098ea42e5d (patch)
treead2df5060759258d225affe6746f23afe26bd23d
parentb1a9c6e00ff713bcbfeb14a1b1215b6d386c6428 (diff)
From Lars Ronald :
MGCP request/response matching and MGCPSTAT RTT calculation. For those with MGCP captures, try -z mgcp,rtd[,filter] svn path=/trunk/; revision=7294
-rw-r--r--AUTHORS4
-rw-r--r--Makefile.am3
-rw-r--r--Makefile.nmake3
-rw-r--r--epan/plugins.c8
-rw-r--r--plugins/mgcp/packet-mgcp.c342
-rwxr-xr-xplugins/mgcp/packet-mgcp.h53
-rw-r--r--plugins/plugin_api.c5
-rw-r--r--plugins/plugin_api.h8
-rw-r--r--plugins/plugin_api_decls.h4
-rw-r--r--plugins/plugin_table.h5
-rw-r--r--tap-mgcpstat.c249
11 files changed, 650 insertions, 34 deletions
diff --git a/AUTHORS b/AUTHORS
index 506a477267..fd2e5979eb 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1631,6 +1631,10 @@ Laurent Meyer <laurent.meyer [AT] thales-avionics.com> {
X.25 reassembly
}
+Lars Ronald <Lars.Roland [AT] gmx.net> {
+ MGCP request/response matching and MGCPSTAT calculation
+}
+
And assorted fixes and enhancements by the people listed above and by:
Pavel Roskin <proski [AT] gnu.org>
diff --git a/Makefile.am b/Makefile.am
index c3cd81ffd0..81afca8c94 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,7 @@
# Makefile.am
# Automake file for Ethereal
#
-# $Id: Makefile.am,v 1.564 2003/03/04 04:11:44 gerald Exp $
+# $Id: Makefile.am,v 1.565 2003/03/06 09:01:40 sahlberg Exp $
#
# Ethereal - Network traffic analyzer
# By Gerald Combs <gerald@ethereal.com>
@@ -806,6 +806,7 @@ TETHEREAL_TAP_SRC = \
tap-dcerpcstat.c \
tap-iostat.c \
tap-iousers.c \
+ tap-mgcpstat.c \
tap-protocolinfo.c \
tap-protohierstat.c \
tap-rpcstat.c \
diff --git a/Makefile.nmake b/Makefile.nmake
index b9aa2f16b5..7fabd50fb9 100644
--- a/Makefile.nmake
+++ b/Makefile.nmake
@@ -1,7 +1,7 @@
## Makefile for building ethereal.exe with Microsoft C and nmake
## Use: $(MAKE) /$(MAKEFLAGS) -f makefile.nmake
#
-# $Id: Makefile.nmake,v 1.284 2003/03/02 21:52:09 guy Exp $
+# $Id: Makefile.nmake,v 1.285 2003/03/06 09:01:40 sahlberg Exp $
include config.nmake
include <win32.mak>
@@ -357,6 +357,7 @@ TETHEREAL_TAP_SRC = \
tap-dcerpcstat.c \
tap-iostat.c \
tap-iousers.c \
+ tap-mgcpstat.c \
tap-protocolinfo.c \
tap-protohierstat.c \
tap-rpcstat.c \
diff --git a/epan/plugins.c b/epan/plugins.c
index 092968b984..af21a5185a 100644
--- a/epan/plugins.c
+++ b/epan/plugins.c
@@ -1,7 +1,7 @@
/* plugins.c
* plugin routines
*
- * $Id: plugins.c,v 1.62 2002/12/08 22:22:03 guy Exp $
+ * $Id: plugins.c,v 1.63 2003/03/06 09:01:43 sahlberg Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -65,6 +65,7 @@
#include "packet-giop.h"
#include "packet-tpkt.h"
#include "packet-tcp.h"
+#include "tap.h"
#include "plugins/plugin_table.h"
static plugin_address_table_t patable;
#endif
@@ -487,7 +488,10 @@ init_plugins(const char *plugin_dir)
patable.p_fragment_delete = fragment_delete;
patable.p_show_fragment_tree = show_fragment_tree;
patable.p_show_fragment_seq_tree = show_fragment_seq_tree;
-
+
+ patable.p_register_tap = register_tap;
+ patable.p_tap_queue_packet = tap_queue_packet;
+
#endif
#ifdef WIN32
diff --git a/plugins/mgcp/packet-mgcp.c b/plugins/mgcp/packet-mgcp.c
index c5cf133652..61bc016f8a 100644
--- a/plugins/mgcp/packet-mgcp.c
+++ b/plugins/mgcp/packet-mgcp.c
@@ -2,7 +2,7 @@
* Routines for mgcp packet disassembly
* RFC 2705
*
- * $Id: packet-mgcp.c,v 1.35 2002/08/28 20:39:07 jmayer Exp $
+ * $Id: packet-mgcp.c,v 1.36 2003/03/06 09:01:47 sahlberg Exp $
*
* Copyright (c) 2000 by Ed Warnicke <hagbard@physics.rutgers.edu>
*
@@ -43,6 +43,8 @@
#include <epan/resolv.h>
#include "prefs.h"
#include <epan/strutil.h>
+#include <epan/conversation.h>
+#include "packet-mgcp.h"
#include "plugins/plugin_api_defs.h"
@@ -65,7 +67,10 @@ static int proto_mgcp = -1;
static int hf_mgcp_req = -1;
static int hf_mgcp_req_verb = -1;
static int hf_mgcp_req_endpoint = -1;
+static int hf_mgcp_req_frame = -1;
static int hf_mgcp_rsp = -1;
+static int hf_mgcp_rsp_frame = -1;
+static int hf_mgcp_time = -1;
static int hf_mgcp_transid = -1;
static int hf_mgcp_version = -1;
static int hf_mgcp_rsp_rspcode = -1;
@@ -97,6 +102,9 @@ static int hf_mgcp_param_capabilities = -1;
static int hf_mgcp_param_extention = -1;
static int hf_mgcp_param_invalid = -1;
static int hf_mgcp_messagecount = -1;
+static int hf_mgcp_dup = -1;
+static int hf_mgcp_req_dup = -1;
+static int hf_mgcp_rsp_dup = -1;
/*
* Define the trees for mgcp
@@ -105,6 +113,10 @@ static int hf_mgcp_messagecount = -1;
static int ett_mgcp = -1;
static int ett_mgcp_param = -1;
+/*
+ * Define the tap for mgcp
+ */
+static int mgcp_tap = -1;
/*
* Here are the global variables associated with
@@ -140,14 +152,6 @@ static int gateway_udp_port = 0;
static int callagent_tcp_port = 0;
static int callagent_udp_port = 0;
-
-/* A simple MGCP type that is occasionally handy */
-typedef enum _mgcp_type {
- MGCP_REQUEST,
- MGCP_RESPONSE,
- MGCP_OTHERS
-} mgcp_type_t;
-
/* Some basic utility functions that are specific to this dissector */
static gboolean is_mgcp_verb(tvbuff_t *tvb, gint offset, gint maxlength);
static gboolean is_mgcp_rspcode(tvbuff_t *tvb, gint offset, gint maxlength);
@@ -161,8 +165,8 @@ static gint tvb_parse_param(tvbuff_t *tvb, gint offset, gint maxlength,
*/
static void dissect_mgcp_message(tvbuff_t *tvb, packet_info *pinfo,
proto_tree *tree,proto_tree *mgcp_tree, proto_tree *ti);
-static void dissect_mgcp_firstline(tvbuff_t *tvb,
- proto_tree *tree);
+static void dissect_mgcp_firstline(tvbuff_t *tvb, packet_info *pinfo,
+ proto_tree *tree, mgcp_info_t *mi);
static void dissect_mgcp_params(tvbuff_t *tvb,
proto_tree *tree);
static void mgcp_raw_text_add(tvbuff_t *tvb,
@@ -181,6 +185,43 @@ static gboolean is_rfc2234_alpha(guint8 c);
static dissector_handle_t sdp_handle;
+
+/*
+ * Init Hash table stuff
+ */
+
+typedef struct _mgcp_call_info_key {
+ guint32 transid;
+ conversation_t *conversation;
+} mgcp_call_info_key;
+
+static GMemChunk *mgcp_call_info_key_chunk;
+
+static GMemChunk *mgcp_call_info_value_chunk;
+
+static GHashTable *mgcp_calls;
+
+/* compare 2 keys */
+static gint
+mgcp_call_equal(gconstpointer k1, gconstpointer k2)
+{
+ const mgcp_call_info_key* key1 = (const mgcp_call_info_key*) k1;
+ const mgcp_call_info_key* key2 = (const mgcp_call_info_key*) k2;
+
+ return (key1->transid == key2->transid &&
+ key1->conversation == key2->conversation);
+}
+
+
+/* calculate a hash key */
+static guint
+mgcp_call_hash(gconstpointer k)
+{
+ const mgcp_call_info_key* key = (const mgcp_call_info_key*) k;
+
+ return key->transid + (guint32)(key->conversation);
+}
+
/*
* dissect_mgcp - The dissector for the Media Gateway Control Protocol
*/
@@ -273,7 +314,7 @@ dissect_mgcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
if (check_col(pinfo->cinfo, COL_INFO) ){
sectionlen = tvb_find_line_end(tvb, tvb_sectionbegin,-1,
&tvb_sectionend,FALSE);
- col_add_fstr(pinfo->cinfo, COL_INFO, "%s",
+ col_prepend_fstr(pinfo->cinfo, COL_INFO, "%s",
tvb_format_text(tvb,tvb_sectionbegin,sectionlen));
}
}
@@ -287,7 +328,8 @@ dissect_mgcp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
gint sectionlen;
gint tvb_sectionend,tvb_sectionbegin, tvb_len, tvb_current_len;
tvbuff_t *next_tvb;
-
+ static mgcp_info_t mi;
+
/* Initialize variables */
tvb_sectionend = 0;
tvb_sectionbegin = tvb_sectionend;
@@ -312,8 +354,8 @@ dissect_mgcp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
sectionlen = tvb_find_line_end(tvb,0,-1,&tvb_sectionend,FALSE);
if( sectionlen > 0){
dissect_mgcp_firstline(tvb_new_subset(tvb, tvb_sectionbegin,
- sectionlen,-1),
- mgcp_tree);
+ sectionlen,-1), pinfo,
+ mgcp_tree, &mi);
}
tvb_sectionbegin = tvb_sectionend;
@@ -373,6 +415,35 @@ static void mgcp_raw_text_add(tvbuff_t *tvb, proto_tree *tree){
} while ( tvb_lineend < tvb_len );
}
+/* Discard and init any state we've saved */
+
+static void
+mgcp_init_protocol(void)
+{
+ if (mgcp_calls != NULL) {
+ g_hash_table_destroy(mgcp_calls);
+ mgcp_calls = NULL;
+ }
+ if (mgcp_call_info_key_chunk != NULL) {
+ g_mem_chunk_destroy(mgcp_call_info_key_chunk);
+ mgcp_call_info_key_chunk = NULL;
+ }
+ if (mgcp_call_info_value_chunk != NULL) {
+ g_mem_chunk_destroy(mgcp_call_info_value_chunk);
+ mgcp_call_info_value_chunk = NULL;
+ }
+
+ mgcp_calls = g_hash_table_new(mgcp_call_hash, mgcp_call_equal);
+ mgcp_call_info_key_chunk = g_mem_chunk_new("call_info_key_chunk",
+ sizeof(mgcp_call_info_key),
+ 200 * sizeof(mgcp_call_info_key),
+ G_ALLOC_ONLY);
+ mgcp_call_info_value_chunk = g_mem_chunk_new("call_info_value_chunk",
+ sizeof(mgcp_call_t),
+ 200 * sizeof(mgcp_call_t),
+ G_ALLOC_ONLY);
+}
+
/* Register all the bits needed with the filtering engine */
void
@@ -385,6 +456,15 @@ proto_register_mgcp(void)
{ &hf_mgcp_rsp,
{ "Response", "mgcp.rsp", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
"TRUE if MGCP response", HFILL }},
+ { &hf_mgcp_req_frame,
+ { "Request Frame", "mgcp.reqframe", FT_FRAMENUM, BASE_NONE, NULL, 0,
+ "Request Frame", HFILL }},
+ { &hf_mgcp_rsp_frame,
+ { "Response Frame", "mgcp.rspframe", FT_FRAMENUM, BASE_NONE, NULL, 0,
+ "Response Frame", HFILL }},
+ { &hf_mgcp_time,
+ { "Time from request", "mgcp.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0,
+ "Timedelta between Request and Response", HFILL }},
{ &hf_mgcp_req_verb,
{ "Verb", "mgcp.req.verb", FT_STRING, BASE_DEC, NULL, 0x0,
"Name of the verb", HFILL }},
@@ -484,6 +564,15 @@ proto_register_mgcp(void)
{ &hf_mgcp_messagecount,
{ "MGCP Message Count", "mgcp.messagecount", FT_UINT32,
BASE_DEC, NULL, 0x0, "Number of MGCP message in a packet", HFILL }},
+ { &hf_mgcp_dup,
+ { "Duplicate Message", "mgcp.dup", FT_UINT32, BASE_DEC,
+ NULL, 0, "Duplicate Message", HFILL }},
+ { &hf_mgcp_req_dup,
+ { "Duplicate Request", "mgcp.req.dup", FT_UINT32, BASE_DEC,
+ NULL, 0, "Duplicate Request", HFILL }},
+ { &hf_mgcp_rsp_dup,
+ { "Duplicate Response", "mgcp.rsp.dup", FT_UINT32, BASE_DEC,
+ NULL, 0, "Duplicate Response", HFILL }},
/* Add more fields here */
};
static gint *ett[] = {
@@ -497,6 +586,7 @@ proto_register_mgcp(void)
proto_register_field_array(proto_mgcp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
+ register_init_routine(&mgcp_init_protocol);
/* Register our configuration options for , particularly our ports */
@@ -548,6 +638,8 @@ proto_register_mgcp(void)
"Display the number of MGCP messages "
"found in a packet in the protocol column.",
&global_mgcp_message_count);
+
+ mgcp_tap = register_tap("mgcp");
}
/* The registration hand-off routine */
@@ -864,17 +956,28 @@ static gint tvb_parse_param(tvbuff_t* tvb, gint offset, gint len, int** hf){
* tree - The tree from which to hang the structured information parsed
* from the first line of the MGCP message.
*/
-static void dissect_mgcp_firstline(tvbuff_t *tvb,
- proto_tree *tree){
+static void dissect_mgcp_firstline(tvbuff_t *tvb, packet_info *pinfo,
+ proto_tree *tree, mgcp_info_t *mi){
gint tvb_current_offset,tvb_previous_offset,tvb_len,tvb_current_len;
gint tokennum, tokenlen;
+ char *transid = NULL;
+ char *code = NULL;
mgcp_type_t mgcp_type = MGCP_OTHERS;
+ conversation_t* conversation;
+ mgcp_call_info_key mgcp_call_key;
+ mgcp_call_info_key *new_mgcp_call_key = NULL;
+ mgcp_call_t *mgcp_call = NULL;
+ nstime_t delta;
+
+ static address null_address = { AT_NONE, 0, NULL };
proto_item* (*my_proto_tree_add_string)(proto_tree*, int, tvbuff_t*, gint,
gint, const char*);
tvb_previous_offset = 0;
tvb_len = tvb_length(tvb);
tvb_current_len = tvb_len;
tvb_current_offset = tvb_previous_offset;
+ mi->is_duplicate = FALSE;
+ mi->request_available = FALSE;
if(tree){
tokennum = 0;
@@ -898,29 +1001,33 @@ static void dissect_mgcp_firstline(tvbuff_t *tvb,
tokenlen = tvb_current_offset - tvb_previous_offset;
}
if(tokennum == 0){
+ code = g_malloc(tokenlen);
+ code = tvb_format_text(tvb,tvb_previous_offset,tokenlen);
+ strncpy(mi->code,code,4);
+ mi->code[4] = '\0';
if(is_mgcp_verb(tvb,tvb_previous_offset,tvb_current_len)){
mgcp_type = MGCP_REQUEST;
my_proto_tree_add_string(tree,hf_mgcp_req_verb, tvb,
tvb_previous_offset, tokenlen,
- tvb_format_text(tvb,tvb_previous_offset
- ,tokenlen));
+ code);
}
else if (is_mgcp_rspcode(tvb,tvb_previous_offset,tvb_current_len)){
mgcp_type = MGCP_RESPONSE;
my_proto_tree_add_string(tree,hf_mgcp_rsp_rspcode, tvb,
tvb_previous_offset, tokenlen,
- tvb_format_text(tvb,tvb_previous_offset
- ,tokenlen));
+ code);
}
else {
break;
}
}
if(tokennum == 1){
+ transid = g_malloc(tokenlen);
+ transid = tvb_format_text(tvb,tvb_previous_offset,tokenlen);
+ mi->transid = atol(transid);
my_proto_tree_add_string(tree,hf_mgcp_transid, tvb,
tvb_previous_offset, tokenlen,
- tvb_format_text(tvb,tvb_previous_offset,
- tokenlen));
+ transid);
}
if(tokennum == 2){
if(mgcp_type == MGCP_REQUEST){
@@ -967,15 +1074,200 @@ static void dissect_mgcp_firstline(tvbuff_t *tvb,
&& tokennum <= 3);
switch (mgcp_type){
case MGCP_RESPONSE:
- proto_tree_add_boolean_hidden(tree, hf_mgcp_rsp, tvb, 0, 0, TRUE);
+ proto_tree_add_boolean_hidden(tree, hf_mgcp_rsp, tvb, 0, 0, TRUE);
+ /* Check for MGCP response. A response must match a call that
+ we've seen, and the response must be sent to the same
+ port and address that the call came from, and must
+ come from the port to which the call was sent.
+
+ If the transport is connection-oriented (we check, for
+ now, only for "pinfo->ptype" of PT_TCP), we take
+ into account the address from which the call was sent
+ and the address to which the call was sent, because
+ the addresses of the two endpoints should be the same
+ for all calls and replies.
+
+ If the transport is connectionless, we don't worry
+ about the address to which the call was sent and from
+ which the reply was sent, because there's no
+ guarantee that the reply will come from the address
+ to which the call was sent. */
+ if (pinfo->ptype == PT_TCP) {
+ conversation = find_conversation(&pinfo->src,
+ &pinfo->dst, pinfo->ptype, pinfo->srcport,
+ pinfo->destport, 0);
+ } else {
+ /*
+ * XXX - can we just use NO_ADDR_B? Unfortunately,
+ * you currently still have to pass a non-null
+ * pointer for the second address argument even
+ * if you do that.
+ */
+ conversation = find_conversation(&null_address,
+ &pinfo->dst, pinfo->ptype, pinfo->srcport,
+ pinfo->destport, 0);
+ }
+ if (conversation != NULL) {
+ /* look only for matching request, if
+ matching conversation is available. */
+ mgcp_call_key.transid = mi->transid;
+ mgcp_call_key.conversation = conversation;
+ mgcp_call = g_hash_table_lookup(mgcp_calls, &mgcp_call_key);
+ if(mgcp_call) {
+ /* Indicate the frame to which this is a reply. */
+ if(mgcp_call->req_num){
+ mi->request_available = TRUE;
+ mgcp_call->responded = TRUE;
+ proto_tree_add_uint_format(tree, hf_mgcp_req_frame,
+ tvb, 0, 0, mgcp_call->req_num,
+ "This is a response to a request in frame %u",
+ mgcp_call->req_num);
+ delta.secs= pinfo->fd->abs_secs-mgcp_call->req_time.secs;
+ delta.nsecs=pinfo->fd->abs_usecs*1000-mgcp_call->req_time.nsecs;
+ if(delta.nsecs<0){
+ delta.nsecs+=1000000000;
+ delta.secs--;
+ }
+ proto_tree_add_time(tree, hf_mgcp_time, tvb, 0, 0,
+ &delta);
+ }
+
+ if (mgcp_call->rsp_num == 0) {
+ /* We have not yet seen a response to that call, so
+ this must be the first response; remember its
+ frame number. */
+ mgcp_call->rsp_num = pinfo->fd->num;
+ } else {
+ /* We have seen a response to this call - but was it
+ *this* response? */
+ if (mgcp_call->rsp_num != pinfo->fd->num) {
+ /* No, so it's a duplicate response.
+ Mark it as such. */
+ mi->is_duplicate = TRUE;
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_fstr(pinfo->cinfo, COL_INFO,
+ ", Duplicate Response %ld",mi->transid);
+ if (tree) {
+ proto_tree_add_uint_hidden(tree,
+ hf_mgcp_dup, tvb, 0,0, mi->transid);
+ proto_tree_add_uint_hidden(tree,
+ hf_mgcp_rsp_dup, tvb, 0,0, mi->transid);
+ }
+ }
+ }
+ }
+ }
+ }
break;
case MGCP_REQUEST:
- proto_tree_add_boolean_hidden(tree, hf_mgcp_req, tvb, 0, 0, TRUE);
+ proto_tree_add_boolean_hidden(tree, hf_mgcp_req, tvb, 0, 0, TRUE);
+ /* Keep track of the address and port whence the call came,
+ and the port to which the call is being sent, so that
+ we can match up calls with replies.
+
+ If the transport is connection-oriented (we check, for
+ now, only for "pinfo->ptype" of PT_TCP), we take
+ into account the address from which the call was sent
+ and the address to which the call was sent, because
+ the addresses of the two endpoints should be the same
+ for all calls and replies.
+
+ If the transport is connectionless, we don't worry
+ about the address to which the call was sent and from
+ which the reply was sent, because there's no
+ guarantee that the reply will come from the address
+ to which the call was sent. */
+ if (pinfo->ptype == PT_TCP) {
+ conversation = find_conversation(&pinfo->src,
+ &pinfo->dst, pinfo->ptype, pinfo->srcport,
+ pinfo->destport, 0);
+ } else {
+ /*
+ * XXX - can we just use NO_ADDR_B? Unfortunately,
+ * you currently still have to pass a non-null
+ * pointer for the second address argument even
+ * if you do that.
+ */
+ conversation = find_conversation(&pinfo->src,
+ &null_address, pinfo->ptype, pinfo->srcport,
+ pinfo->destport, 0);
+ }
+ if (conversation == NULL) {
+ /* It's not part of any conversation - create a new
+ one. */
+ if (pinfo->ptype == PT_TCP) {
+ conversation = conversation_new(&pinfo->src,
+ &pinfo->dst, pinfo->ptype, pinfo->srcport,
+ pinfo->destport, 0);
+ } else {
+ conversation = conversation_new(&pinfo->src,
+ &null_address, pinfo->ptype, pinfo->srcport,
+ pinfo->destport, 0);
+ }
+ }
+
+ /* prepare the key data */
+ mgcp_call_key.transid = mi->transid;
+ mgcp_call_key.conversation = conversation;
+
+ /* look up the request */
+ mgcp_call = g_hash_table_lookup(mgcp_calls, &mgcp_call_key);
+ if (mgcp_call != NULL) {
+ /* We've seen a request with this TRANSID, with the same
+ source and destination, before - but was it
+ *this* request? */
+ if (pinfo->fd->num != mgcp_call->req_num) {
+ /* No, so it's a duplicate request.
+ Mark it as such. */
+ mi->is_duplicate = TRUE;
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_fstr(pinfo->cinfo, COL_INFO,
+ ", Duplicate Request %ld",mi->transid);
+ if (tree) {
+ proto_tree_add_uint_hidden(tree,
+ hf_mgcp_dup, tvb, 0,0, mi->transid);
+ proto_tree_add_uint_hidden(tree,
+ hf_mgcp_req_dup, tvb, 0,0, mi->transid);
+ }
+ }
+ }
+ }
+ else {
+ /* Prepare the value data.
+ "req_num" and "rsp_num" are frame numbers;
+ frame numbers are 1-origin, so we use 0
+ to mean "we don't yet know in which frame
+ the reply for this call appears". */
+ new_mgcp_call_key = g_mem_chunk_alloc(mgcp_call_info_key_chunk);
+ *new_mgcp_call_key = mgcp_call_key;
+ mgcp_call = g_mem_chunk_alloc(mgcp_call_info_value_chunk);
+ mgcp_call->req_num = pinfo->fd->num;
+ mgcp_call->rsp_num = 0;
+ mgcp_call->transid = mi->transid;
+ mgcp_call->responded = FALSE;
+ mgcp_call->req_time.secs=pinfo->fd->abs_secs;
+ mgcp_call->req_time.nsecs=pinfo->fd->abs_usecs*1000;
+ strcpy(mgcp_call->code,mi->code);
+ /* store it */
+ g_hash_table_insert(mgcp_calls, new_mgcp_call_key, mgcp_call);
+ }
+ if(mgcp_call && mgcp_call->rsp_num){
+ proto_tree_add_uint_format(tree, hf_mgcp_rsp_frame,
+ tvb, 0, 0, mgcp_call->rsp_num,
+ "The response to this request is in frame %u",
+ mgcp_call->rsp_num);
+ }
break;
default:
break;
}
+ mi->mgcp_type = mgcp_type;
+ if(mgcp_call) {
+ mi->req_time.secs=mgcp_call->req_time.secs;
+ mi->req_time.nsecs=mgcp_call->req_time.nsecs;
+ }
}
+ tap_queue_packet(mgcp_tap, pinfo, mi);
}
/*
diff --git a/plugins/mgcp/packet-mgcp.h b/plugins/mgcp/packet-mgcp.h
new file mode 100755
index 0000000000..b7dbf3a339
--- /dev/null
+++ b/plugins/mgcp/packet-mgcp.h
@@ -0,0 +1,53 @@
+/* packet-mgcp.h
+ * Routines for mgcp packet disassembly
+ * RFC 2705
+ *
+ * $Id: packet-mgcp.h,v 1.1 2003/03/06 09:01:47 sahlberg Exp $
+ *
+ * Copyright (c) 2000 by Ed Warnicke <hagbard@physics.rutgers.edu>
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1999 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+ /* A simple MGCP type that is occasionally handy */
+typedef enum _mgcp_type {
+ MGCP_REQUEST,
+ MGCP_RESPONSE,
+ MGCP_OTHERS
+} mgcp_type_t;
+
+/* Container for tapping relevant data */
+typedef struct _mgcp_info_t {
+ mgcp_type_t mgcp_type;
+ char code[5];
+ guint32 transid;
+ nstime_t req_time;
+ gboolean is_duplicate;
+ gboolean request_available;
+} mgcp_info_t;
+
+/* Item of request list */
+typedef struct _mgcp_call_t {
+ guint32 transid;
+ char code[5];
+ guint32 req_num; /* frame number request seen */
+ guint32 rsp_num; /* frame number response seen */
+ nstime_t req_time;
+ gboolean responded;
+} mgcp_call_t;
diff --git a/plugins/plugin_api.c b/plugins/plugin_api.c
index 88b0278dd3..50bbfcfc2a 100644
--- a/plugins/plugin_api.c
+++ b/plugins/plugin_api.c
@@ -1,7 +1,7 @@
/* plugin_api.c
* Routines for Ethereal plugins.
*
- * $Id: plugin_api.c,v 1.43 2002/11/14 18:54:53 guy Exp $
+ * $Id: plugin_api.c,v 1.44 2003/03/06 09:01:44 sahlberg Exp $
*
* Ethereal - Network traffic analyzer
* Copyright 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
@@ -210,4 +210,7 @@ plugin_address_table_init(plugin_address_table_t *pat)
p_fragment_delete = pat->p_fragment_delete;
p_show_fragment_tree = pat->p_show_fragment_tree;
p_show_fragment_seq_tree = pat->p_show_fragment_seq_tree;
+
+ p_register_tap = pat->p_register_tap;
+ p_tap_queue_packet = pat->p_tap_queue_packet;
}
diff --git a/plugins/plugin_api.h b/plugins/plugin_api.h
index 0cc32a5193..04fb8c5c3d 100644
--- a/plugins/plugin_api.h
+++ b/plugins/plugin_api.h
@@ -1,7 +1,7 @@
/* plugin_api.h
* Routines for Ethereal plugins.
*
- * $Id: plugin_api.h,v 1.44 2002/11/14 18:54:53 guy Exp $
+ * $Id: plugin_api.h,v 1.45 2003/03/06 09:01:45 sahlberg Exp $
*
* Ethereal - Network traffic analyzer
* Copyright 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
@@ -240,7 +240,10 @@
#define fragment_delete (*p_fragment_delete)
#define show_fragment_tree (*p_show_fragment_tree)
#define show_fragment_seq_tree (*p_show_fragment_seq_tree)
-
+
+#define register_tap (*p_register_tap)
+#define tap_queue_packet (*p_tap_queue_packet)
+
#endif
#include <epan/packet.h>
@@ -250,6 +253,7 @@
#include "packet-giop.h"
#include "packet-tpkt.h"
#include "packet-tcp.h"
+#include "tap.h"
#include "plugin_table.h"
diff --git a/plugins/plugin_api_decls.h b/plugins/plugin_api_decls.h
index fb45ac30e8..427f1b48e3 100644
--- a/plugins/plugin_api_decls.h
+++ b/plugins/plugin_api_decls.h
@@ -2,7 +2,7 @@
* Declarations of a list of "p_" names; included in various places
* to declare them as variables or as function members.
*
- * $Id: plugin_api_decls.h,v 1.6 2002/11/14 18:54:53 guy Exp $
+ * $Id: plugin_api_decls.h,v 1.7 2003/03/06 09:01:45 sahlberg Exp $
*
* Ethereal - Network traffic analyzer
* Copyright 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
@@ -250,3 +250,5 @@ addr_fragment_delete p_fragment_delete;
addr_show_fragment_tree p_show_fragment_tree;
addr_show_fragment_seq_tree p_show_fragment_seq_tree;
+addr_register_tap p_register_tap;
+addr_tap_queue_packet p_tap_queue_packet;
diff --git a/plugins/plugin_table.h b/plugins/plugin_table.h
index 38e0f53a57..3e53a9ae52 100644
--- a/plugins/plugin_table.h
+++ b/plugins/plugin_table.h
@@ -1,7 +1,7 @@
/* plugin_table.h
* Table of exported addresses for Ethereal plugins.
*
- * $Id: plugin_table.h,v 1.56 2002/12/02 23:34:40 guy Exp $
+ * $Id: plugin_table.h,v 1.57 2003/03/06 09:01:45 sahlberg Exp $
*
* Ethereal - Network traffic analyzer
* Copyright 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
@@ -279,6 +279,9 @@ typedef unsigned char *(*addr_fragment_delete)(packet_info *, guint32, GHashTabl
typedef gboolean (*addr_show_fragment_tree)(fragment_data *, const fragment_items *, proto_tree *, packet_info *, tvbuff_t *);
typedef gboolean (*addr_show_fragment_seq_tree)(fragment_data *, const fragment_items *, proto_tree *, packet_info *, tvbuff_t *);
+typedef int (*addr_register_tap)(char *);
+typedef void (*addr_tap_queue_packet)(int, packet_info *, void *);
+
typedef struct {
#include "plugin_api_decls.h"
diff --git a/tap-mgcpstat.c b/tap-mgcpstat.c
new file mode 100644
index 0000000000..3547b35d26
--- /dev/null
+++ b/tap-mgcpstat.c
@@ -0,0 +1,249 @@
+/* tap-mgcpstat.c
+ * mgcpstat 2003 Lars Roland
+ *
+ * $Id: tap-mgcpstat.c,v 1.1 2003/03/06 09:01:40 sahlberg Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#include <string.h>
+#include "epan/packet_info.h"
+#include "tap.h"
+#include "epan/value_string.h"
+#include "register.h"
+#include "plugins/mgcp/packet-mgcp.h"
+
+
+/* Summary of response-time calculations*/
+typedef struct _rtd_t {
+ long int num;
+ nstime_t min;
+ nstime_t max;
+ nstime_t tot;
+} rtd_t;
+
+/* used to keep track of the statistics for an entire program interface */
+typedef struct _mgcpstat_t {
+ char *filter;
+ rtd_t rtd;
+ long int open_req_num;
+ long int disc_rsp_num;
+ long int req_dup_num;
+ long int rsp_dup_num;
+} mgcpstat_t;
+
+/* A Function to update a mgcp_rtd_t struct */
+
+void
+rtd_stat_update(rtd_t *rtd,nstime_t delta)
+{
+ rtd->num++;
+ if((rtd->max.secs==0)
+ && (rtd->max.nsecs==0) ){
+ rtd->max.secs=delta.secs;
+ rtd->max.nsecs=delta.nsecs;
+ }
+
+ if((rtd->min.secs==0)
+ && (rtd->min.nsecs==0) ){
+ rtd->min.secs=delta.secs;
+ rtd->min.nsecs=delta.nsecs;
+ }
+
+ if( (delta.secs<rtd->min.secs)
+ ||( (delta.secs==rtd->min.secs)
+ &&(delta.nsecs<rtd->min.nsecs) ) ){
+ rtd->min.secs=delta.secs;
+ rtd->min.nsecs=delta.nsecs;
+ }
+
+ if( (delta.secs>rtd->max.secs)
+ ||( (delta.secs==rtd->max.secs)
+ &&(delta.nsecs>rtd->max.nsecs) ) ){
+ rtd->max.secs=delta.secs;
+ rtd->max.nsecs=delta.nsecs;
+ }
+
+ rtd->tot.secs += delta.secs;
+ rtd->tot.nsecs += delta.nsecs;
+ if(rtd->tot.nsecs>1000000000){
+ rtd->tot.nsecs-=1000000000;
+ rtd->tot.secs++;
+ }
+
+
+}
+
+static int
+mgcpstat_packet(void *pms, packet_info *pinfo, epan_dissect_t *edt _U_, void *pmi)
+{
+ mgcpstat_t *ms=(mgcpstat_t *)pms;
+ mgcp_info_t *mi=pmi;
+ nstime_t delta;
+
+ switch (mi->mgcp_type) {
+
+ case MGCP_REQUEST:
+ if(mi->is_duplicate){
+ /* Duplicate is ignored */
+ ms->req_dup_num++;
+ return 0;
+ }
+ else {
+ ms->open_req_num++;
+ return 0;
+ }
+ break;
+
+ case MGCP_RESPONSE:
+ if(mi->is_duplicate){
+ /* Duplicate is ignored */
+ ms->rsp_dup_num++;
+ return 0;
+ }
+ else if (!mi->request_available) {
+ /* no request was seen */
+ ms->disc_rsp_num++;
+ return 0;
+ }
+ else {
+ ms->open_req_num--;
+ /* calculate time delta between request and response */
+ delta.secs=pinfo->fd->abs_secs-mi->req_time.secs;
+ delta.nsecs=pinfo->fd->abs_usecs*1000-mi->req_time.nsecs;
+ if(delta.nsecs<0){
+ delta.nsecs+=1000000000;
+ delta.secs--;
+ }
+
+ rtd_stat_update(&(ms->rtd),delta);
+ return 1;
+ }
+ break;
+
+ default:
+ return 0;
+ break;
+ }
+}
+
+static void
+mgcpstat_draw(void *pms)
+{
+ mgcpstat_t *ms=(mgcpstat_t *)pms;
+
+#ifdef G_HAVE_UINT64
+ guint64 avg;
+#else
+ guint32 avg;
+#endif
+
+
+ /* calculating average rtd */
+ /* scale it to units of 10us.*/
+ /* for long captures with a large tot time, this can overflow on 32bit */
+ avg=(int)ms->rtd.tot.secs;
+ avg=avg*100000+(int)ms->rtd.tot.nsecs/10000;
+ if(ms->rtd.num){
+ avg/=ms->rtd.num;
+ } else {
+ avg=0;
+ }
+
+ /* printing results */
+ printf("\n");
+ printf("===================================================================\n");
+ printf("MGCP Response Time Delay (RTD) Statistics:\n");
+ printf("Filter: %s\n",ms->filter?ms->filter:"");
+ printf("Duplicate requests: %ld\n",ms->req_dup_num);
+ printf("Duplicate responses: %ld\n",ms->rsp_dup_num);
+ printf("Open requests: %ld\n",ms->open_req_num);
+ printf("Discarded responses: %ld\n",ms->disc_rsp_num);
+ printf("Messages | Min RTD | Max RTD | Avg RTD \n");
+ printf("%7ld | %5d.%03d msec | %5d.%03d msec | %5d.%03d msec\n",
+ ms->rtd.num,
+ (int)((ms->rtd.min.secs*1000)+(ms->rtd.min.nsecs/1000000)),(ms->rtd.min.nsecs%1000000)/1000,
+ (int)((ms->rtd.max.secs*1000)+(ms->rtd.max.nsecs/1000000)),(ms->rtd.min.nsecs%1000000)/1000,
+ avg/100, avg%100
+ );
+ printf("===================================================================\n");
+}
+
+
+static void
+mgcpstat_init(char *optarg)
+{
+ mgcpstat_t *ms;
+ char *filter=NULL;
+
+
+ if(!strncmp(optarg,"mgcp,rtd,",9)){
+ filter=optarg+9;
+ } else {
+ filter=NULL;
+ }
+
+ ms=g_malloc(sizeof(mgcpstat_t));
+ if(filter){
+ ms->filter=g_malloc(strlen(filter)+1);
+ strcpy(ms->filter, filter);
+ } else {
+ ms->filter=NULL;
+ }
+
+ ms->rtd.num=0;
+ ms->rtd.min.secs=0;
+ ms->rtd.min.nsecs=0;
+ ms->rtd.max.secs=0;
+ ms->rtd.max.nsecs=0;
+ ms->rtd.tot.secs=0;
+ ms->rtd.tot.nsecs=0;
+
+ ms->open_req_num=0;
+ ms->disc_rsp_num=0;
+ ms->req_dup_num=0;
+ ms->rsp_dup_num=0;
+
+ if(register_tap_listener("mgcp", ms, filter, NULL, mgcpstat_packet, mgcpstat_draw)){
+ /* error, we failed to attach to the tap. clean up */
+ g_free(ms->filter);
+ g_free(ms);
+
+ fprintf(stderr,"tethereal: mgcpstat_init() failed to attach to tap.\n");
+ exit(1);
+ }
+}
+
+
+void
+register_tap_listener_mgcpstat(void)
+{
+ register_ethereal_tap("mgcp,rtd", mgcpstat_init, NULL, NULL);
+}
+