diff options
author | Ronnie Sahlberg <ronnie_sahlberg@ozemail.com.au> | 2003-03-06 09:01:47 +0000 |
---|---|---|
committer | Ronnie Sahlberg <ronnie_sahlberg@ozemail.com.au> | 2003-03-06 09:01:47 +0000 |
commit | e00fb8c41365618d603fb0c8943540098ea42e5d (patch) | |
tree | ad2df5060759258d225affe6746f23afe26bd23d | |
parent | b1a9c6e00ff713bcbfeb14a1b1215b6d386c6428 (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-- | AUTHORS | 4 | ||||
-rw-r--r-- | Makefile.am | 3 | ||||
-rw-r--r-- | Makefile.nmake | 3 | ||||
-rw-r--r-- | epan/plugins.c | 8 | ||||
-rw-r--r-- | plugins/mgcp/packet-mgcp.c | 342 | ||||
-rwxr-xr-x | plugins/mgcp/packet-mgcp.h | 53 | ||||
-rw-r--r-- | plugins/plugin_api.c | 5 | ||||
-rw-r--r-- | plugins/plugin_api.h | 8 | ||||
-rw-r--r-- | plugins/plugin_api_decls.h | 4 | ||||
-rw-r--r-- | plugins/plugin_table.h | 5 | ||||
-rw-r--r-- | tap-mgcpstat.c | 249 |
11 files changed, 650 insertions, 34 deletions
@@ -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);
+}
+
|