Ethereal-dev: Re: [Ethereal-dev] Voip Calls analysis and Graph analysis

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Alejandro Vaquero <alejandrovaquero@xxxxxxxxx>
Date: Sun, 06 Feb 2005 20:40:22 -0700
Hi All,
    Find attached a patch for "Voip analysis" to get the LRQ/LCF/LRJ messages included in the H323 calls for Gatekeeper to Gatekeeper configurations.

Regards
Alejandro

Alejandro Vaquero wrote:
Hi All,
   Attached a patch that to shows the RTP streams in the Graph. Now using an RTP tap (not using the rtp_stream).

Regards
Alejandro

Alejandro Vaquero wrote:

Hi Lars and All,
   Thanks to test and add this. I'll work on get the RTP back using a tap for RTP.

Regards
Alejandro



Lars Roland wrote:

Hello all,

I've just patched the new VoIP call analysis feature from Alejandro Vaquero.
It should work now reliable enough to add it to the distribution. I hope it compiles with GTK1.2, too. no problem with GTK 1.3 and GTK 2.4 on windows.

Unfortunately I had to disable support for showing rtp streams in call flows. The responsible function does not work in the current implementation. After all I am surprised that it worked at least partly before.

However I'd like to thank Alejandro for his excellent work.

IMO the buggy h323 conversation tap is obsolete now. It is surpassed by the VoIP Call Analysis.
Does anyone have any objections against removing it?

Regards,
Lars



_______________________________________________
Ethereal-dev mailing list
Ethereal-dev@xxxxxxxxxxxx
http://www.ethereal.com/mailman/listinfo/ethereal-dev


_______________________________________________
Ethereal-dev mailing list
Ethereal-dev@xxxxxxxxxxxx
http://www.ethereal.com/mailman/listinfo/ethereal-dev


Index: gtk/voip_calls_dlg.c =================================================================== --- gtk/voip_calls_dlg.c (revision 13232) +++ gtk/voip_calls_dlg.c (working copy) @@ -174,6 +174,7 @@ remove_tap_listener_h245dg_calls(); remove_tap_listener_q931_calls(); remove_tap_listener_sdp_calls(); + remove_tap_listener_rtp(); } /****************************************************************************/ @@ -605,11 +606,6 @@ gchar label_text[256]; if (voip_calls_dlg != NULL) { - - /* Add the RTP streams info for the graph */ - /* deactivated for now */ -/* add_rtp_streams_graph(); */ - gtk_clist_clear(GTK_CLIST(clist)); calls_nb = 0; calls_ns = 0; @@ -674,6 +670,7 @@ h245dg_calls_init_tap(); q931_calls_init_tap(); sdp_calls_init_tap(); + rtp_init_tap(); /* init the Graph Analysys */ graph_analysis_data = graph_analysis_init(); Index: gtk/voip_calls.c =================================================================== --- gtk/voip_calls.c (revision 13232) +++ gtk/voip_calls.c (working copy) @@ -92,8 +92,9 @@ static voip_calls_tapinfo_t the_tapinfo_struct = {0, NULL, 0, NULL, 0, 0, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0}; -/* static voip_calls_tapinfo_t the_tapinfo_struct; -*/ +/* the one and only global voip_rtp_tapinfo_t structure */ +static voip_rtp_tapinfo_t the_tapinfo_rtp_struct = + {0, NULL, 0}; /****************************************************************************/ /* when there is a [re]reading of packet's */ @@ -173,81 +174,6 @@ } /****************************************************************************/ -/* Add the RTP streams into the graph data */ -/** - * TODO: - * - reimplement this function - * This function does not work with VoIP taps - * which keep the window up to date. - * Either make rtp_stream() work without redissection or - * add an additional tap listener for rtp to this file. - * The second solution is cleaner and probably easier to implement, - * leaving the current rtp analysis feature untouched. - */ -void add_rtp_streams_graph() -{ - rtp_stream_info_t *strinfo; - GList *strinfo_list; - guint nfound; - guint item; - GList* voip_calls_graph_list; - graph_analysis_item_t *gai; - graph_analysis_item_t *new_gai; - guint16 conv_num; - guint32 duration; - - /* Scan for rtpstream */ - rtpstream_scan(); - - /* assigne the RTP streams to calls */ - nfound = 0; - strinfo_list = g_list_first(rtpstream_get_info()->strinfo_list); - while (strinfo_list) - { - strinfo = (rtp_stream_info_t*)(strinfo_list->data); - - /* look in the voip calls graph list if there is a match for this RTP stream */ - voip_calls_graph_list = g_list_first(the_tapinfo_struct.graph_analysis->list); - item = 0; - while (voip_calls_graph_list) - { - gai = voip_calls_graph_list->data; - conv_num = gai->conv_num; - if (strinfo->setup_frame_number == gai->frame_num){ - while(voip_calls_graph_list){ - gai = voip_calls_graph_list->data; - /* add the RTP item to the graph */ - if (strinfo->first_frame_num<gai->frame_num){ - new_gai = g_malloc(sizeof(graph_analysis_item_t)); - new_gai->frame_num = strinfo->first_frame_num; - new_gai->time = (double)strinfo->start_rel_sec + (double)strinfo->start_rel_usec/1000000; - g_memmove(&new_gai->ip_src, strinfo->src_addr.data, 4); - g_memmove(&new_gai->ip_dst, strinfo->dest_addr.data, 4); - new_gai->port_src = strinfo->src_port; - new_gai->port_dst = strinfo->dest_port; - duration = (strinfo->stop_rel_sec*1000000 + strinfo->stop_rel_usec) - (strinfo->start_rel_sec*1000000 + strinfo->start_rel_usec); - new_gai->frame_label = g_strdup_printf("RTP (%s)", val_to_str(strinfo->pt, rtp_payload_type_short_vals, "%u")); - new_gai->comment = g_strdup_printf("RTP Num packets:%d Duration:%d.%03ds ssrc:%d", strinfo->npackets, duration/1000000,(duration%1000000)/1000, strinfo->ssrc); - new_gai->conv_num = conv_num; - new_gai->display=FALSE; - new_gai->line_style = 2; /* the arrow line will be 2 pixels width */ - the_tapinfo_struct.graph_analysis->list = g_list_insert(the_tapinfo_struct.graph_analysis->list, new_gai, item); - - break; - } - voip_calls_graph_list = g_list_next(voip_calls_graph_list); - item++; - } - break; - } - voip_calls_graph_list = g_list_next(voip_calls_graph_list); - item++; - } - strinfo_list = g_list_next(strinfo_list); - } -} - -/****************************************************************************/ /* Add a new item into the graph */ int add_to_graph(voip_calls_tapinfo_t *tapinfo _U_, packet_info *pinfo, gchar *frame_label, gchar *comment, guint16 call_num) { @@ -317,6 +243,193 @@ } /****************************************************************************/ +/* ***************************TAP for RTP **********************************/ +/****************************************************************************/ + +/****************************************************************************/ +/* when there is a [re]reading of RTP packet's */ +void voip_rtp_reset(voip_rtp_tapinfo_t *tapinfo) +{ + GList* list; + /* free the data items first */ + list = g_list_first(tapinfo->list); + while (list) + { + g_free(list->data); + list = g_list_next(list); + } + g_list_free(tapinfo->list); + tapinfo->list = NULL; + tapinfo->nstreams = 0; + return; +} + +/****************************************************************************/ +/* whenever a RTP packet is seen by the tap listener */ +static int +RTP_packet( void *ptr _U_, packet_info *pinfo, epan_dissect_t *edt _U_, const void *RTPinfo) +{ + voip_rtp_tapinfo_t *tapinfo = &the_tapinfo_rtp_struct; + voip_rtp_stream_info_t *tmp_listinfo; + voip_rtp_stream_info_t *strinfo = NULL; + GList* list; + + const struct _rtp_info *pi = RTPinfo; + + /* do not consider RTP packets without a setup frame */ + if (pi->info_setup_frame_num == 0){ + return 0; + } + + /* check wether we already have a RTP stream with this setup frame and ssrc in the list */ + list = g_list_first(tapinfo->list); + while (list) + { + tmp_listinfo=list->data; + if ( (tmp_listinfo->setup_frame_number == pi->info_setup_frame_num) && (tmp_listinfo->ssrc == pi->info_sync_src) ){ + strinfo = (voip_rtp_stream_info_t*)(list->data); + break; + } + list = g_list_next (list); + } + + /* not in the list? then create a new entry */ + if (strinfo==NULL){ + strinfo = g_malloc(sizeof(voip_rtp_stream_info_t)); + COPY_ADDRESS(&(strinfo->src_addr), &(pinfo->src)); + strinfo->src_port = pinfo->srcport; + COPY_ADDRESS(&(strinfo->dest_addr), &(pinfo->dst)); + strinfo->dest_port = pinfo->destport; + strinfo->ssrc = pi->info_sync_src; + strinfo->pt = pi->info_payload_type; + strinfo->npackets = 0; + strinfo->first_frame_num = pinfo->fd->num; + strinfo->start_rel_sec = pinfo->fd->rel_secs; + strinfo->start_rel_usec = pinfo->fd->rel_usecs; + strinfo->setup_frame_number = pi->info_setup_frame_num; + tapinfo->list = g_list_append(tapinfo->list, strinfo); + } + + if (strinfo!=NULL){ + /* Add the info to the existing RTP stream */ + strinfo->npackets++; + strinfo->stop_rel_sec = pinfo->fd->rel_secs; + strinfo->stop_rel_usec = pinfo->fd->rel_usecs; + } + return 1; +} + +/****************************************************************************/ +/* whenever a redraw in the RTP tap listener */ +void RTP_packet_draw(void *prs _U_) +{ + voip_rtp_tapinfo_t *rtp_tapinfo = &the_tapinfo_rtp_struct; + GList* rtp_streams_list; + voip_rtp_stream_info_t *rtp_listinfo; + GList* voip_calls_graph_list; + guint item; + graph_analysis_item_t *gai; + graph_analysis_item_t *new_gai; + guint16 conv_num; + guint32 duration; + + /* add each rtp stream to the graph */ + rtp_streams_list = g_list_first(rtp_tapinfo->list); + while (rtp_streams_list) + { + rtp_listinfo = rtp_streams_list->data; + + /* using the setup frame number of the RTP stream, we get the call number that it belongs */ + voip_calls_graph_list = g_list_first(the_tapinfo_struct.graph_analysis->list); + item = 0; + while (voip_calls_graph_list) + { + gai = voip_calls_graph_list->data; + conv_num = gai->conv_num; + /* if we get the setup frame number, then get the time position to graph the RTP arrow */ + if (rtp_listinfo->setup_frame_number == gai->frame_num){ + while(voip_calls_graph_list){ + gai = voip_calls_graph_list->data; + /* if RTP was already in the Graph, just update the comment information */ + if (rtp_listinfo->first_frame_num == gai->frame_num){ + duration = (rtp_listinfo->stop_rel_sec*1000000 + rtp_listinfo->stop_rel_usec) - (rtp_listinfo->start_rel_sec*1000000 + rtp_listinfo->start_rel_usec); + g_free(gai->comment); + gai->comment = g_strdup_printf("RTP Num packets:%d Duration:%d.%03ds ssrc:%d", rtp_listinfo->npackets, duration/1000000,(duration%1000000)/1000, rtp_listinfo->ssrc); + break; + /* add the RTP item to the graph if was not there*/ + } else if (rtp_listinfo->first_frame_num<gai->frame_num){ + new_gai = g_malloc(sizeof(graph_analysis_item_t)); + new_gai->frame_num = rtp_listinfo->first_frame_num; + new_gai->time = (double)rtp_listinfo->start_rel_sec + (double)rtp_listinfo->start_rel_usec/1000000; + g_memmove(&new_gai->ip_src, rtp_listinfo->src_addr.data, 4); + g_memmove(&new_gai->ip_dst, rtp_listinfo->dest_addr.data, 4); + new_gai->port_src = rtp_listinfo->src_port; + new_gai->port_dst = rtp_listinfo->dest_port; + duration = (rtp_listinfo->stop_rel_sec*1000000 + rtp_listinfo->stop_rel_usec) - (rtp_listinfo->start_rel_sec*1000000 + rtp_listinfo->start_rel_usec); + new_gai->frame_label = g_strdup_printf("RTP (%s)", val_to_str(rtp_listinfo->pt, rtp_payload_type_short_vals, "%u")); + new_gai->comment = g_strdup_printf("RTP Num packets:%d Duration:%d.%03ds ssrc:%d", rtp_listinfo->npackets, duration/1000000,(duration%1000000)/1000, rtp_listinfo->ssrc); + new_gai->conv_num = conv_num; + new_gai->display=FALSE; + new_gai->line_style = 2; /* the arrow line will be 2 pixels width */ + the_tapinfo_struct.graph_analysis->list = g_list_insert(the_tapinfo_struct.graph_analysis->list, new_gai, item); + break; + } + + voip_calls_graph_list = g_list_next(voip_calls_graph_list); + item++; + } + break; + } + voip_calls_graph_list = g_list_next(voip_calls_graph_list); + item++; + } + rtp_streams_list = g_list_next(rtp_streams_list); + } +} + +static gboolean have_RTP_tap_listener=FALSE; +/****************************************************************************/ +void +rtp_init_tap(void) +{ + GString *error_string; + + if(have_RTP_tap_listener==FALSE) + { + /* don't register tap listener, if we have it already */ + error_string = register_tap_listener("rtp", &(the_tapinfo_rtp_struct), NULL, + voip_rtp_reset, + RTP_packet, + RTP_packet_draw + ); + if (error_string != NULL) { + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, + error_string->str); + g_string_free(error_string, TRUE); + exit(1); + } + have_RTP_tap_listener=TRUE; + } +} + + + +/* XXX just copied from gtk/rpc_stat.c */ +void protect_thread_critical_region(void); +void unprotect_thread_critical_region(void); + +/****************************************************************************/ +void +remove_tap_listener_rtp(void) +{ + protect_thread_critical_region(); + remove_tap_listener(&(the_tapinfo_rtp_struct.rtp_dummy)); + unprotect_thread_critical_region(); + + have_RTP_tap_listener=FALSE; +} + +/****************************************************************************/ /* ***************************TAP for SIP **********************************/ /****************************************************************************/ Index: gtk/voip_calls.h =================================================================== --- gtk/voip_calls.h (revision 13232) +++ gtk/voip_calls.h (working copy) @@ -38,6 +38,7 @@ #include <glib.h> #include <stdio.h> +#include <epan/address.h> /****************************************************************************/ /* defines voip call state */ @@ -150,6 +151,33 @@ } voip_calls_tapinfo_t; +/* defines a RTP stream */ +typedef struct _voip_rtp_stream_info { + address src_addr; + guint16 src_port; + address dest_addr; + guint16 dest_port; + guint32 ssrc; + guint8 pt; + guint32 npackets; + + guint32 first_frame_num; /* frame number of first frame */ + guint32 setup_frame_number; /* frame number of setup message */ + /* start of recording (GMT) of this stream */ + guint32 start_rel_sec; /* start stream rel seconds */ + guint32 start_rel_usec; /* start stream rel microseconds */ + guint32 stop_rel_sec; /* stop stream rel seconds */ + guint32 stop_rel_usec; /* stop stream rel microseconds */ +} voip_rtp_stream_info_t; + +/* structure that holds the information about all RTP streams associated with the calls */ +/* struct holding all information of the RTP tap */ +typedef struct _voip_rtp_tapinfo { + int nstreams; /* number of rtp streams */ + GList* list; /* list with the rtp streams */ + int rtp_dummy; +} voip_rtp_tapinfo_t; + /****************************************************************************/ /* INTERFACE */ @@ -167,6 +195,7 @@ void h245dg_calls_init_tap(void); void q931_calls_init_tap(void); void sdp_calls_init_tap(void); +void rtp_init_tap(void); /* @@ -180,6 +209,7 @@ void remove_tap_listener_h245dg_calls(void); void remove_tap_listener_q931_calls(void); void remove_tap_listener_sdp_calls(void); +void remove_tap_listener_rtp(void); /* * Retrieves a constant reference to the unique info structure of the voip_calls tap listener. Index: epan/dissectors/packet-rtp.c =================================================================== --- epan/dissectors/packet-rtp.c (revision 13232) +++ epan/dissectors/packet-rtp.c (working copy) @@ -353,6 +353,8 @@ proto_tree_add_item( rtp_tree, hf_rtp_data, newtvb, 0, -1, FALSE ); } +static struct _rtp_info rtp_info; + static void dissect_rtp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree ) { @@ -377,8 +379,6 @@ guint32 sync_src; guint32 csrc_item; - static struct _rtp_info rtp_info; - /* Get the fields in the first octet */ octet1 = tvb_get_guint8( tvb, offset ); version = RTP_VERSION( octet1 ); @@ -430,6 +430,7 @@ rtp_info.info_seq_num = seq_num; rtp_info.info_timestamp = timestamp; rtp_info.info_sync_src = sync_src; + rtp_info.info_setup_frame_num = 0; /* * Do we have all the data? @@ -517,6 +518,7 @@ proto_tree_add_uint( rtp_tree, hf_rtp_ssrc, tvb, offset, 4, sync_src ); offset += 4; } else { + show_setup_info(tvb, pinfo, NULL); offset += 12; } /* CSRC list*/ @@ -653,7 +655,7 @@ /* Look for conversation info and display any setup info found */ -void show_setup_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +static void show_setup_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { /* Conversation and current data */ conversation_t *p_conv = NULL; @@ -705,6 +707,7 @@ tvb, 0, 0, p_conv_data->method); PROTO_ITEM_SET_GENERATED(item); } + rtp_info.info_setup_frame_num = p_conv_data->frame_number; } } Index: epan/dissectors/packet-rtp.h =================================================================== --- epan/dissectors/packet-rtp.h (revision 13232) +++ epan/dissectors/packet-rtp.h (working copy) @@ -40,6 +40,7 @@ gboolean info_all_data_present; /* FALSE if data is cut off */ guint info_payload_offset; /* start of payload relative to info_data */ guint info_payload_len; /* length of payload (incl padding) */ + guint32 info_setup_frame_num; /* the frame num of the packet that set this RTP connection */ const guint8* info_data; /* pointer to raw rtp data */ /* * info_data: pointer to raw rtp data = "" + payload incl. padding.
Index: tools/asn2eth.py
===================================================================
--- tools/asn2eth.py	(revision 13312)
+++ tools/asn2eth.py	(working copy)
@@ -2746,7 +2746,8 @@
       if (ectx.OPer()):
         body = ectx.eth_fn_call('dissect_per_restricted_character_string', ret='offset',
                                 par=(('tvb', 'offset', 'pinfo', 'tree', 'hf_index'),
-                                     (minv, maxv, alphabet, alphabet_length)))
+								     (minv, maxv, alphabet, alphabet_length),
+									 ('NULL', 'NULL')))                                     
       else:
         body = '#error Can not decode %s' % (tname)
     elif (ectx.NPer()):
Index: asn1/h225/packet-h225-template.c
===================================================================
--- asn1/h225/packet-h225-template.c	(revision 13312)
+++ asn1/h225/packet-h225-template.c	(working copy)
@@ -298,6 +298,8 @@
 	pi->h245_address = 0;
 	pi->h245_port = 0;
 	pi->frame_label[0] = '\0';
+	pi->dialedDigits[0] = '\0';
+	pi->is_destinationInfo = FALSE;
 }
 
 /*
Index: asn1/h225/packet-h225-template.h
===================================================================
--- asn1/h225/packet-h225-template.h	(revision 13312)
+++ asn1/h225/packet-h225-template.h	(working copy)
@@ -65,6 +65,8 @@
 	gboolean is_h245Tunneling;
 	guint32 h245_address;
 	guint16 h245_port;
+	gchar dialedDigits[64]; /* Dialed Digits in the LRQ and LCF used for voip analysis */
+	gboolean is_destinationInfo;
 	gchar frame_label[50]; /* the Fram label used by graph_analysis, what is a abreviation of cinfo */
 } h225_packet_info;
 
Index: asn1/h225/h225.cnf
===================================================================
--- asn1/h225/h225.cnf	(revision 13312)
+++ asn1/h225/h225.cnf	(working copy)
@@ -203,16 +203,25 @@
 	h225_pi->msg_tag = rasmessage_value;
 #.END
 #----------------------------------------------------------------------------------------
+#.FN_HDR DestinationInfo/_item
+
+  h225_pi->is_destinationInfo = TRUE;
+#.END
+#----------------------------------------------------------------------------------------
 # TODO asn2eth can't handle restriced string ?
 #.FN_BODY DialedDigits
-
-	offset=dissect_per_restricted_character_string(tvb, offset, pinfo, tree, hf_index, 1, 128, "#,*0123456789", 13);
+  if (h225_pi->is_destinationInfo == TRUE) {
+    offset = dissect_per_restricted_character_string(tvb, offset, pinfo, tree, hf_index, 1, 128, "#,*0123456789", 13, (char *)&h225_pi->dialedDigits , 64);  
+	h225_pi->is_destinationInfo = FALSE;
+  }
+  else
+	offset = dissect_per_restricted_character_string(tvb, offset, pinfo, tree, hf_index, 1, 128, "#,*0123456789", 13, NULL, NULL);
 #.END
 #----------------------------------------------------------------------------------------
 # TODO asn2eth can't handle restriced string ?
 #.FN_BODY NumberDigits
 
-	offset=dissect_per_restricted_character_string(tvb, offset, pinfo, tree, hf_index, 1, 128, "#,*0123456789", 13);
+	offset=dissect_per_restricted_character_string(tvb, offset, pinfo, tree, hf_index, 1, 128, "#,*0123456789", 13, NULL, NULL);
 #.END
 #----------------------------------------------------------------------------------------
 #.FN_BODY H245TransportAddress/h245ipAddress/h245ipv4
Index: gtk/voip_calls_dlg.c
===================================================================
--- gtk/voip_calls_dlg.c	(revision 13312)
+++ gtk/voip_calls_dlg.c	(working copy)
@@ -154,7 +154,7 @@
 	/* Update the status label with the number of total messages */
         g_snprintf(label_text, 256,
        		"Total: Calls: %d   Start packets: %d   Completed calls: %d   Rejected calls: %d",
-			voip_calls_get_info()->ncalls,
+			g_list_length(voip_calls_get_info()->strinfo_list),
 			voip_calls_get_info()->start_packets, 
 			voip_calls_get_info()->completed_calls,
 			voip_calls_get_info()->rejected_calls);
@@ -604,19 +604,20 @@
 void voip_calls_dlg_update(GList *list)
 {
 	gchar label_text[256];
-
+guint foo;
 	if (voip_calls_dlg != NULL) {
 		gtk_clist_clear(GTK_CLIST(clist));
 		calls_nb = 0;
 		calls_ns = 0;
         	g_snprintf(label_text, 256,
         		"Total: Calls: %d   Start packets: %d   Completed calls: %d   Rejected calls: %d",
-			voip_calls_get_info()->ncalls,
+			g_list_length(voip_calls_get_info()->strinfo_list),
 		        voip_calls_get_info()->start_packets, 
 			voip_calls_get_info()->completed_calls,
 			voip_calls_get_info()->rejected_calls);
         	gtk_label_set(GTK_LABEL(status_label), label_text);
 
+		foo=	g_list_length(list);
 		list = g_list_first(list);
 		while (list)
 		{
Index: gtk/voip_calls.c
===================================================================
--- gtk/voip_calls.c	(revision 13312)
+++ gtk/voip_calls.c	(working copy)
@@ -174,81 +174,6 @@
 }
 
 /****************************************************************************/
-/* Add the RTP streams into the graph data */
-/** 
- * TODO: 
- * - reimplement this function
- * This function does not work with VoIP taps
- * which keep the window up to date.
- * Either make rtp_stream() work without redissection or
- * add an additional tap listener for rtp to this file.
- * The second solution is cleaner and probably easier to implement, 
- * leaving the current rtp analysis feature untouched.
- */
-void add_rtp_streams_graph(void)
-{
-	rtp_stream_info_t *strinfo;
-	GList *strinfo_list;
-	guint nfound;
-	guint item;
-	GList* voip_calls_graph_list;
-	graph_analysis_item_t *gai;
-	graph_analysis_item_t *new_gai;
-	guint16 conv_num;
-	guint32 duration;
-
-	/* Scan for rtpstream */
-	rtpstream_scan();
-
-	/* assigne the RTP streams to calls */
-	nfound = 0;
-	strinfo_list = g_list_first(rtpstream_get_info()->strinfo_list);
-	while (strinfo_list)
-	{
-		strinfo = (rtp_stream_info_t*)(strinfo_list->data);
-
-		/* look in the voip calls graph list if there is a match for this RTP stream */
-		voip_calls_graph_list = g_list_first(the_tapinfo_struct.graph_analysis->list);
-		item = 0;
-		while (voip_calls_graph_list)
-		{			
-			gai = voip_calls_graph_list->data;
-			conv_num = gai->conv_num;
-			if (strinfo->setup_frame_number == gai->frame_num){
-				while(voip_calls_graph_list){
-					gai = voip_calls_graph_list->data;
-					/* add the RTP item to the graph */
-					if (strinfo->first_frame_num<gai->frame_num){
-						new_gai = g_malloc(sizeof(graph_analysis_item_t));
-						new_gai->frame_num = strinfo->first_frame_num;
-						new_gai->time = (double)strinfo->start_rel_sec + (double)strinfo->start_rel_usec/1000000;
-						g_memmove(&new_gai->ip_src, strinfo->src_addr.data, 4);
-						g_memmove(&new_gai->ip_dst, strinfo->dest_addr.data, 4);
-						new_gai->port_src = strinfo->src_port;
-						new_gai->port_dst = strinfo->dest_port;
-						duration = (strinfo->stop_rel_sec*1000000 + strinfo->stop_rel_usec) - (strinfo->start_rel_sec*1000000 + strinfo->start_rel_usec);
-						new_gai->frame_label = g_strdup_printf("RTP (%s)", val_to_str(strinfo->pt, rtp_payload_type_short_vals, "%u"));
-						new_gai->comment = g_strdup_printf("RTP Num packets:%d  Duration:%d.%03ds ssrc:%d", strinfo->npackets, duration/1000000,(duration%1000000)/1000, strinfo->ssrc);
-						new_gai->conv_num = conv_num;
-						new_gai->display=FALSE;
-						new_gai->line_style = 2;  /* the arrow line will be 2 pixels width */
-						the_tapinfo_struct.graph_analysis->list = g_list_insert(the_tapinfo_struct.graph_analysis->list, new_gai, item);
-						
-						break;
-					}
-					voip_calls_graph_list = g_list_next(voip_calls_graph_list);
-					item++;
-				}
-				break;
-			}
-			voip_calls_graph_list = g_list_next(voip_calls_graph_list);
-			item++;
-		}
-		strinfo_list = g_list_next(strinfo_list);
-	}
-}
-
-/****************************************************************************/
 /* Add a new item into the graph */
 int add_to_graph(voip_calls_tapinfo_t *tapinfo _U_, packet_info *pinfo, gchar *frame_label, gchar *comment, guint16 call_num)
 {
@@ -318,6 +243,28 @@
 }
 
 /****************************************************************************/
+/* Change all the graph items with call_num to new_call_num */
+guint change_call_num_graph(voip_calls_tapinfo_t *tapinfo _U_, guint16 call_num, guint16 new_call_num)
+{
+	graph_analysis_item_t *gai;
+	GList* list;
+	guint items_changed;
+
+	items_changed = 0;
+	list = g_list_first(tapinfo->graph_analysis->list);
+	while (list)
+	{
+		gai = list->data;
+		if (gai->conv_num == call_num){
+			gai->conv_num = new_call_num;
+			items_changed++;
+		}
+		list = g_list_next (list);
+	}
+	return items_changed;
+}
+
+/****************************************************************************/
 /* ***************************TAP for RTP **********************************/
 /****************************************************************************/
 
@@ -1085,15 +1032,17 @@
 	voip_calls_info_t *tmp_listinfo;
 	voip_calls_info_t *strinfo = NULL;
 	h323_calls_info_t *tmp_h323info;
+	h323_calls_info_t *tmp2_h323info;
 	gchar *frame_label;
 	gchar *comment;
 	GList* list;
 	guint32 tmp_src, tmp_dst;
+	guint foo;
 
 	const h225_packet_info *pi = H225info;
 
-	/* if not guid and RAS return because did not belong to a call */
-	if ((memcmp(pi->guid, guid_allzero, GUID_LEN) == 0) && (pi->msg_type == H225_RAS))
+	/* if not guid and RAS and not LRQ, LCF or LRJ return because did not belong to a call */
+	if ((memcmp(pi->guid, guid_allzero, GUID_LEN) == 0) && (pi->msg_type == H225_RAS) && ((pi->msg_tag < 18) || (pi->msg_tag > 20)))
 		return 0;
 	
 
@@ -1113,6 +1062,24 @@
 			list = g_list_next (list);
 		}
 		if (strinfo==NULL) 	return 0;		
+	} else if ( (pi->msg_type == H225_RAS) && ((pi->msg_tag == 19) || (pi->msg_tag == 20))) { /* RAS LCF or LRJ*/
+		/* if the LCF/LRJ doesn't match to a LRQ, just return */
+		if (!pi->request_available) return 0;
+
+		/* check wether we already have a call with this request SeqNum */
+		list = g_list_first(tapinfo->strinfo_list);
+		while (list)
+		{
+			tmp_listinfo=list->data;
+			if (tmp_listinfo->protocol == VOIP_H323){
+				tmp_h323info = tmp_listinfo->prot_info;
+				if (tmp_h323info->requestSeqNum == pi->requestSeqNum) {
+					strinfo = (voip_calls_info_t*)(list->data);
+					break;
+				}
+			}
+			list = g_list_next (list);
+		}
 	} else {
 		/* check wether we already have a call with this guid in the list */
 		list = g_list_first(tapinfo->strinfo_list);
@@ -1121,7 +1088,7 @@
 			tmp_listinfo=list->data;
 			if (tmp_listinfo->protocol == VOIP_H323){
 				tmp_h323info = tmp_listinfo->prot_info;
-				if (memcmp(tmp_h323info->guid, pi->guid,GUID_LEN)==0){ 
+				if ( (memcmp(tmp_h323info->guid, guid_allzero, GUID_LEN) != 0) && (memcmp(tmp_h323info->guid, pi->guid,GUID_LEN)==0) ){ 
 					strinfo = (voip_calls_info_t*)(list->data);
 					break;
 				}
@@ -1155,6 +1122,7 @@
 		tmp_h323info->is_h245 = FALSE;
 		tmp_h323info->q931_crv = -1;
 		tmp_h323info->q931_crv2 = -1;
+		tmp_h323info->requestSeqNum = 0;
 		strinfo->call_num = tapinfo->ncalls++;
 		strinfo->npackets = 0;
 
@@ -1194,7 +1162,6 @@
 			switch(pi->cs_type){
 			case H225_SETUP:
 				tmp_h323info->is_faststart_Setup = pi->is_faststart;
-
 				/* set te calling and called number from the Q931 packet */
 				if (q931_frame_num == pinfo->fd->num){
 					if (q931_calling_number != NULL){
@@ -1206,6 +1173,39 @@
 						strinfo->to_identity=g_strdup(q931_called_number);
 					}
 				}
+				/* check if there is an LRQ/LCF that match this Setup */
+				/* TODO: we are just checking the DialedNumer in LRQ/LCF agains the Setup 
+				  we should also check if the h225 signaling IP and port match the destination 
+				  Setup ip and port */
+				list = g_list_first(tapinfo->strinfo_list);
+						foo=	g_list_length(list);
+				while (list)
+				{
+					tmp_listinfo=list->data;
+					if (tmp_listinfo->protocol == VOIP_H323){
+						tmp2_h323info = tmp_listinfo->prot_info;
+
+						/* check if there called number match a LRQ/LCF */
+						if ( (strcmp(strinfo->to_identity, tmp_listinfo->to_identity)==0)  
+								&& (memcmp(tmp2_h323info->guid, guid_allzero, GUID_LEN) == 0) ){ 
+							/* change the call graph to the LRQ/LCF to belong to this call */
+							strinfo->npackets += change_call_num_graph(tapinfo, tmp_listinfo->call_num, strinfo->call_num);
+
+							/* remove this LRQ/LCF call entry because we have found the Setup that match them */
+							g_free(tmp_listinfo->from_identity);
+							g_free(tmp_listinfo->to_identity);
+							g_free(tmp2_h323info->guid);
+							g_list_free(tmp2_h323info->h245_list);
+							tmp2_h323info->h245_list = NULL;		
+							g_free(tmp_listinfo->prot_info);
+							tapinfo->strinfo_list = g_list_remove(tapinfo->strinfo_list, tmp_listinfo);
+							break;
+						}
+					}
+					list = g_list_next (list);
+				}
+						foo=	g_list_length(list);
+				/* Set the Setup address if it was not set */
 				if (tmp_h323info->h225SetupAddr == 0) g_memmove(&(tmp_h323info->h225SetupAddr), pinfo->src.data,4);
 				strinfo->call_state=VOIP_CALL_SETUP;
 				comment = g_strdup_printf("H225 From: %s To:%s  TunnH245:%s FS:%s", strinfo->from_identity, strinfo->to_identity, (tmp_h323info->is_h245Tunneling==TRUE?"on":"off"), 
@@ -1253,8 +1253,23 @@
 
 			}
 		} else if (pi->msg_type == H225_RAS){
+			switch(pi->msg_tag){
+			case 18:  /* LRQ */
+				if (!pi->is_duplicate){
+					g_free(strinfo->to_identity);
+					strinfo->to_identity=g_strdup(pi->dialedDigits);
+					tmp_h323info->requestSeqNum = pi->requestSeqNum;
+				}
+			case 19: /* LCF */
+				if (strlen(pi->dialedDigits)) 
+					comment = g_strdup_printf("H225 RAS dialedDigits: %s", pi->dialedDigits);
+				else
+					comment = g_strdup("H225 RAS");
+				break;
+			default:
+				comment = g_strdup("H225 RAS");
+			}
 			frame_label = g_strdup_printf("%s", val_to_str(pi->msg_tag, RasMessage_vals, "<unknown>"));
-			comment = g_strdup("H225 RAS");
 		} else {
 			frame_label = g_strdup("H225: Unknown");
 			comment = g_strdup("");
Index: gtk/voip_calls.h
===================================================================
--- gtk/voip_calls.h	(revision 13312)
+++ gtk/voip_calls.h	(working copy)
@@ -104,6 +104,7 @@
 	gboolean is_h245Tunneling;
 	gint32 q931_crv;
 	gint32 q931_crv2;
+	guint requestSeqNum;
 } h323_calls_info_t;
 
 /* defines a voip call */
@@ -128,7 +129,7 @@
 /* struct holding all information of the tap */
 
 typedef struct _voip_calls_tapinfo {
-	int     ncalls;       /* number of calls in the list */
+	int     ncalls;       /* number of call */
 	GList*  strinfo_list;   /* list with all calls */
 	int     npackets;       /* total number of packets of all calls */
 	voip_calls_info_t* filter_calls_fwd;  /* used as filter in some tap modes */
Index: plugins/plugin_api_list.c
===================================================================
--- plugins/plugin_api_list.c	(revision 13312)
+++ plugins/plugin_api_list.c	(working copy)
@@ -377,7 +377,7 @@
 guint32 dissect_per_choice(tvbuff_t*, guint32, packet_info*, proto_tree*, int, gint, const per_choice_t*, char*, guint32*);
 guint32 dissect_per_sequence(tvbuff_t*, guint32, packet_info*, proto_tree *parent_tree, int, gint, const per_sequence_t*);
 guint32 dissect_per_octet_string(tvbuff_t*, guint32, packet_info*, proto_tree*, int, int, int, guint32*, guint32*);
-guint32 dissect_per_restricted_character_string(tvbuff_t*, guint32, packet_info*, proto_tree*, int, int, int, char*, int);
+guint32 dissect_per_restricted_character_string(tvbuff_t*, guint32, packet_info*, proto_tree*, int, int, int, char*, int, char *, guint32);
 
 void dissector_add_string(const char*, gchar*, dissector_handle_t);
 void dissector_delete_string(const char*, const gchar*,	dissector_handle_t);
Index: plugins/Xplugin_table.h
===================================================================
--- plugins/Xplugin_table.h	(revision 13312)
+++ plugins/Xplugin_table.h	(working copy)
@@ -232,7 +232,7 @@
 typedef guint32 (*addr_dissect_per_choice) (tvbuff_t *, guint32, packet_info *, proto_tree *, int, gint, const per_choice_t *, char *, guint32 *);
 typedef guint32 (*addr_dissect_per_sequence) (tvbuff_t *, guint32, packet_info *, proto_tree *, int, gint, const per_sequence_t *);
 typedef guint32 (*addr_dissect_per_octet_string) (tvbuff_t *, guint32, packet_info *, proto_tree *, int, int, int, guint32 *, guint32 *);
-typedef guint32 (*addr_dissect_per_restricted_character_string) (tvbuff_t *, guint32, packet_info *, proto_tree *, int, int, int, char *, int);
+typedef guint32 (*addr_dissect_per_restricted_character_string) (tvbuff_t *, guint32, packet_info *, proto_tree *, int, int, int, char *, int, char *, guint32);
 typedef void (*addr_dissector_add_string) (const char *, gchar *, dissector_handle_t);
 typedef void (*addr_dissector_delete_string) (const char *, const gchar *, dissector_handle_t);
 typedef void (*addr_dissector_change_string) (const char *, gchar *, dissector_handle_t);
Index: epan/dissectors/packet-h225.c
===================================================================
--- epan/dissectors/packet-h225.c	(revision 13312)
+++ epan/dissectors/packet-h225.c	(working copy)
@@ -744,7 +744,7 @@
 static int hf_h225_gatewayDataRate = -1;          /* DataRate */
 static int hf_h225_desiredTunnelledProtocol = -1;  /* TunnelledProtocol */
 static int hf_h225_canMapSrcAlias = -1;           /* BOOLEAN */
-static int hf_h225_DestinationInfo_item = -1;     /* AliasAddress */
+static int hf_h225_DestinationInfo_item = -1;     /* DestinationInfo_item */
 static int hf_h225_pointToPoint = -1;             /* NULL */
 static int hf_h225_oneToN = -1;                   /* NULL */
 static int hf_h225_nToOne = -1;                   /* NULL */
@@ -2232,9 +2232,13 @@
 
 static int
 dissect_h225_DialedDigits(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index) {
+  if (h225_pi->is_destinationInfo == TRUE) {
+    offset = dissect_per_restricted_character_string(tvb, offset, pinfo, tree, hf_index, 1, 128, "#,*0123456789", 13, (char *)&h225_pi->dialedDigits , 64);  
+	h225_pi->is_destinationInfo = FALSE;
+  }
+  else
+	offset = dissect_per_restricted_character_string(tvb, offset, pinfo, tree, hf_index, 1, 128, "#,*0123456789", 13, NULL, NULL);
 
-	offset=dissect_per_restricted_character_string(tvb, offset, pinfo, tree, hf_index, 1, 128, "#,*0123456789", 13);
-
   return offset;
 }
 static int dissect_dialedDigits(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) {
@@ -2515,7 +2519,7 @@
 static int
 dissect_h225_NumberDigits(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index) {
 
-	offset=dissect_per_restricted_character_string(tvb, offset, pinfo, tree, hf_index, 1, 128, "#,*0123456789", 13);
+	offset=dissect_per_restricted_character_string(tvb, offset, pinfo, tree, hf_index, 1, 128, "#,*0123456789", 13, NULL, NULL);
 
   return offset;
 }
@@ -2649,7 +2653,8 @@
 static int
 dissect_h225_TBCD_STRING(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index) {
   offset = dissect_per_restricted_character_string(tvb, offset, pinfo, tree, hf_index,
-                                                   -1, -1, "0123456789#*abc", strlen("0123456789#*abc"));
+                                                   -1, -1, "0123456789#*abc", strlen("0123456789#*abc"),
+                                                   NULL, NULL);
 
   return offset;
 }
@@ -2914,9 +2919,6 @@
 static int dissect_srcInfo_item(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) {
   return dissect_h225_AliasAddress(tvb, offset, pinfo, tree, hf_h225_srcInfo_item);
 }
-static int dissect_DestinationInfo_item(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) {
-  return dissect_h225_AliasAddress(tvb, offset, pinfo, tree, hf_h225_DestinationInfo_item);
-}
 static int dissect_modifiedSrcInfo_item(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) {
   return dissect_h225_AliasAddress(tvb, offset, pinfo, tree, hf_h225_modifiedSrcInfo_item);
 }
@@ -7584,6 +7586,19 @@
 
 
 static int
+dissect_h225_DestinationInfo_item(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index) {
+
+  h225_pi->is_destinationInfo = TRUE;
+  offset = dissect_h225_AliasAddress(tvb, offset, pinfo, tree, hf_index);
+
+  return offset;
+}
+static int dissect_DestinationInfo_item(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) {
+  return dissect_h225_DestinationInfo_item(tvb, offset, pinfo, tree, hf_h225_DestinationInfo_item);
+}
+
+
+static int
 dissect_h225_DestinationInfo(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index) {
   offset = dissect_per_sequence_of(tvb, offset, pinfo, tree, hf_index,
                                    ett_h225_DestinationInfo, dissect_DestinationInfo_item);
@@ -12274,6 +12289,8 @@
 	pi->h245_address = 0;
 	pi->h245_port = 0;
 	pi->frame_label[0] = '\0';
+	pi->dialedDigits[0] = '\0';
+	pi->is_destinationInfo = FALSE;
 }
 
 /*
Index: epan/dissectors/packet-h225.h
===================================================================
--- epan/dissectors/packet-h225.h	(revision 13312)
+++ epan/dissectors/packet-h225.h	(working copy)
@@ -1,6 +1,6 @@
 /* Do not modify this file.                                                   */
 /* It is created automatically by the ASN.1 to Ethereal dissector compiler    */
-/* .\packet-h225.h                                                            */
+/* ./packet-h225.h                                                            */
 /* ../../tools/asn2eth.py -X -e -p h225 -c h225.cnf -s packet-h225-template h225.asn */
 
 /* Input file: packet-h225-template.h */
@@ -72,6 +72,8 @@
 	gboolean is_h245Tunneling;
 	guint32 h245_address;
 	guint16 h245_port;
+	gchar dialedDigits[64]; /* Dialed Digits in the LRQ and LCF used for voip analysis */
+	gboolean is_destinationInfo;
 	gchar frame_label[50]; /* the Fram label used by graph_analysis, what is a abreviation of cinfo */
 } h225_packet_info;
 
Index: epan/dissectors/packet-per.c
===================================================================
--- epan/dissectors/packet-per.c	(revision 13312)
+++ epan/dissectors/packet-per.c	(working copy)
@@ -269,7 +269,7 @@
 
 /* XXX we dont do >64k length strings   yet */
 guint32
-dissect_per_restricted_character_string(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index, int min_len, int max_len, char *alphabet, int alphabet_length)
+dissect_per_restricted_character_string(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index, int min_len, int max_len, char *alphabet, int alphabet_length, char *info_str, guint32 info_str_len)
 {
 	guint32 length;
 	gboolean byte_aligned;
@@ -282,6 +282,9 @@
 
 	/* xx.x if the length is 0 bytes there will be no encoding */
 	if(max_len==0){
+		if (info_str != NULL) {
+			info_str[0] = '\0';
+		}
 		return offset;
 	}
 
@@ -397,27 +400,30 @@
 	}
 	str[char_pos]=0;
 	proto_tree_add_string(tree, hf_index, tvb, (old_offset>>3), (offset>>3)-(old_offset>>3), str);
-
+	if (info_str != NULL) {
+		if (info_str_len<length) str[info_str_len-1] = '\0';	
+		strcpy(info_str, str);
+	}
 	return offset;
 }
 guint32
 dissect_per_NumericString(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index, int min_len, int max_len)
 {
-	offset=dissect_per_restricted_character_string(tvb, offset, pinfo, tree, hf_index, min_len, max_len, " 0123456789", 11);
+	offset=dissect_per_restricted_character_string(tvb, offset, pinfo, tree, hf_index, min_len, max_len, " 0123456789", 11, NULL, NULL);
 
 	return offset;
 }
 guint32
 dissect_per_PrintableString(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index, int min_len, int max_len)
 {
-	offset=dissect_per_restricted_character_string(tvb, offset, pinfo, tree, hf_index, min_len, max_len, " '()+,-.*0123456789:=?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 74);
+	offset=dissect_per_restricted_character_string(tvb, offset, pinfo, tree, hf_index, min_len, max_len, " '()+,-.*0123456789:=?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 74, NULL, NULL);
 	return offset;
 }
 guint32
 dissect_per_VisibleString(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index, int min_len, int max_len)
 {
 	offset=dissect_per_restricted_character_string(tvb, offset, pinfo, tree, hf_index, min_len, max_len,
-		" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", 95);
+		" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", 95, NULL, NULL);
 	return offset;
 }
 guint32
Index: epan/dissectors/packet-per.h
===================================================================
--- epan/dissectors/packet-per.h	(revision 13312)
+++ epan/dissectors/packet-per.h	(working copy)
@@ -100,6 +100,6 @@
 
 extern guint32 dissect_per_bit_string(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index, int min_len, int max_len);
 
-extern guint32 dissect_per_restricted_character_string(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index, int min_len, int max_len, char *alphabet, int alphabet_length);
+extern guint32 dissect_per_restricted_character_string(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index, int min_len, int max_len, char *alphabet, int alphabet_length, char *info_str, guint32 info_str_len);
 
 #endif  /* __PACKET_PER_H__ */