Ethereal-dev: [Ethereal-dev] Fax t38 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, 02 Oct 2005 13:48:23 -0600
Hi All, Find attached a new "Fax T38 Analysis" added to the "Statistics" menu to: - Reassemble the HDLC t30 frames and dissect the header. - Analyze the UPDTLPacket seq num for packet lost - Stats of V.x Data: - Count the Data bytes - Duration - Wrong seq num - Max Burst of packet lost TODO: dissect the complete t30 frames Regards Alejandro |
Index: gtk/graph_analysis.c =================================================================== --- gtk/graph_analysis.c (revision 16065) +++ gtk/graph_analysis.c (working copy) @@ -136,6 +136,8 @@ user_data->num_nodes = 0; user_data->num_items = 0; + user_data->on_destroy_user_data = NULL; + user_data->data = NULL; for (i=0; i<MAX_NUM_NODES; i++){ user_data->nodes[i].type = AT_NONE; user_data->nodes[i].len = 0; @@ -165,13 +167,14 @@ user_data->dlg.selected_item=0xFFFFFFFF; /*not item selected */ user_data->dlg.window=NULL; user_data->dlg.inverse = FALSE; + user_data->dlg.title=NULL; } /****************************************************************************/ /* CALLBACKS */ /****************************************************************************/ -/* close the dialog window and remove the tap listener */ +/* close the dialog window */ static void on_destroy(GtkWidget *win _U_, graph_analysis_data_t *user_data _U_) { int i; @@ -183,6 +186,12 @@ user_data->nodes[i].data = NULL; } user_data->dlg.window = NULL; + g_free(user_data->dlg.title); + user_data->dlg.title = NULL; + + if(user_data->on_destroy_user_data){ + user_data->on_destroy_user_data(user_data->data); + } } #define RIGHT_ARROW 1 @@ -649,7 +658,7 @@ top_y_border=TOP_Y_BORDER; /* to display the node address */ bottom_y_border=2; - draw_height=user_data->dlg.draw_area->allocation.height-top_y_border-bottom_y_border; + draw_height=user_data->dlg.draw_area->allocation.height-top_y_border-bottom_y_border; first_item = user_data->dlg.first_item; display_items = draw_height/ITEM_HEIGHT; @@ -734,7 +743,7 @@ pango_layout_get_pixel_size(layout, &label_width, &label_height); #endif - /* resize the "time" draw area */ + /* resize the "time" draw area */ left_x_border=3; user_data->dlg.left_x_border = left_x_border; @@ -1359,9 +1368,9 @@ gdk_gc_set_rgb_fg_color(user_data->dlg.bg_gc[i], &col[i]); #endif } + + dialog_graph_redraw(user_data); - dialog_graph_redraw(user_data); - return TRUE; } @@ -1429,6 +1438,7 @@ dialog_graph_redraw(user_data); + return TRUE; } #if GTK_MAJOR_VERSION >= 2 @@ -1561,9 +1571,9 @@ gtk_box_pack_start(GTK_BOX(hbox), user_data->dlg.draw_area_time, FALSE, FALSE, 0); - user_data->dlg.hpane = gtk_hpaned_new(); - gtk_paned_pack1(GTK_PANED (user_data->dlg.hpane), user_data->dlg.scroll_window, FALSE, TRUE); - gtk_paned_pack2(GTK_PANED (user_data->dlg.hpane), scroll_window_comments, TRUE, TRUE); + user_data->dlg.hpane = gtk_hpaned_new(); + gtk_paned_pack1(GTK_PANED (user_data->dlg.hpane), user_data->dlg.scroll_window, FALSE, TRUE); + gtk_paned_pack2(GTK_PANED (user_data->dlg.hpane), scroll_window_comments, TRUE, TRUE); #if GTK_MAJOR_VERSION >= 2 SIGNAL_CONNECT(user_data->dlg.hpane, "notify::position", pane_callback, user_data); #endif @@ -1596,7 +1606,10 @@ GtkTooltips *tooltips = gtk_tooltips_new(); /* create the main window */ - user_data->dlg.window=window_new(GTK_WINDOW_TOPLEVEL, "Graph Analysis"); + if (user_data->dlg.title) + user_data->dlg.window=window_new(GTK_WINDOW_TOPLEVEL, user_data->dlg.title); + else + user_data->dlg.window=window_new(GTK_WINDOW_TOPLEVEL, "Graph Analysis"); vbox=gtk_vbox_new(FALSE, 0); @@ -1787,3 +1800,24 @@ return; } + +/****************************************************************************/ +void graph_analysis_redraw(graph_analysis_data_t* user_data) +{ + /* get nodes (each node is an address) */ + get_nodes(user_data); + + user_data->dlg.pixmap_width = user_data->num_nodes * NODE_WIDTH; + WIDGET_SET_SIZE(user_data->dlg.draw_area, user_data->dlg.pixmap_width, user_data->dlg.pixmap_height); + if ( user_data->num_nodes < 6) + WIDGET_SET_SIZE(user_data->dlg.scroll_window, NODE_WIDTH*user_data->num_nodes, user_data->dlg.pixmap_height); + else + WIDGET_SET_SIZE(user_data->dlg.scroll_window, NODE_WIDTH*5, user_data->dlg.pixmap_height); + + + /* redraw the graph */ + dialog_graph_redraw(user_data); + + window_present(user_data->dlg.window); + return; +} Index: gtk/graph_analysis.h =================================================================== --- gtk/graph_analysis.h (revision 16065) +++ gtk/graph_analysis.h (working copy) @@ -104,10 +104,11 @@ display_items_t items[NUM_DISPLAY_ITEMS]; guint32 left_x_border; char *save_file; + char *title; /* Graph analysis window's title */ } dialog_data_t; +typedef void (*destroy_user_data_cb)(void *data); - /* structure that holds general information and the dialog */ typedef struct _graph_analysis_data_t { /* graphic data */ @@ -118,11 +119,14 @@ address nodes[MAX_NUM_NODES]; guint32 num_nodes; guint32 num_items; + destroy_user_data_cb on_destroy_user_data; /* callback info for destroy */ + void *data; /* data to be passes when on destroy */ } graph_analysis_data_t; graph_analysis_data_t* graph_analysis_init(void); void graph_analysis_create(graph_analysis_data_t* user_data); void graph_analysis_update(graph_analysis_data_t* user_data); +void graph_analysis_redraw(graph_analysis_data_t* user_data); #endif /*GRAPH_ANALYSIS_H_INCLUDED*/ Index: gtk/Makefile.common =================================================================== --- gtk/Makefile.common (revision 16065) +++ gtk/Makefile.common (working copy) @@ -157,6 +157,7 @@ sctp_stat_dlg.c \ sip_stat.c \ smb_stat.c \ + t38_analysis.c \ tcp_graph.c \ voip_calls_dlg.c \ wsp_stat.c Index: gtk/voip_calls.c =================================================================== --- gtk/voip_calls.c (revision 16065) +++ gtk/voip_calls.c (working copy) @@ -168,6 +168,8 @@ graph_item = list->data; g_free(graph_item->frame_label); g_free(graph_item->comment); + g_free((void *)graph_item->src_addr.data); + g_free((void *)graph_item->dst_addr.data); g_free(list->data); list = g_list_next(list); } Index: gtk/t38_analysis.c =================================================================== --- gtk/t38_analysis.c (revision 0) +++ gtk/t38_analysis.c (revision 0) @@ -0,0 +1,738 @@ +/* t38_analysis.c + * t38 fax analysis for ethereal + * + * $Id: voip_calls.c 14867 2005-07-07 04:03:35Z guy $ + * + * Copyright 2005 Verso Technologies Inc. + * By Alejandro Vaquero <alejandro.vaquero@xxxxxxxxx> + * + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@xxxxxxxxxxxx> + * 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 <string.h> + +#include "graph_analysis.h" + +#include "globals.h" + +#include <epan/tap.h> +#include <epan/epan_dissect.h> +#include <epan/dissectors/packet-t38.h> +#include <epan/dissectors/packet-rtp.h> +#include <epan/conversation.h> +#include "../stat_menu.h" + +#include "alert_box.h" +#include "simple_dialog.h" +#include "graph_analysis.h" + +#define MAX_HDLC_FRAME 1024 + +typedef enum { + UNKNOWN, + CORRECT, + EARLY, /* seq_num > than expected, we assume all previous as lost */ + LATE /* seq_num < than expected, late packet we drop it */ +} SEQ_STATUS; + +typedef struct _tap_t38_stat_t { + gboolean first_packet; + gint32 seq_num; /* UDPTLPacket sequence number */ + gint32 wrong_seq_num; /* count UDPTLPacket wron sequence number */ + guint8 hdlc_data[MAX_HDLC_FRAME]; /* V21 HDLC data */ + guint16 hdlc_data_index; /* V21 HDLC index */ + gboolean valid_hdlc_data; + guint32 other_data_num_bytes; /* num of bytes of other data (non hdlc) */ + guint32 other_data_lost; /* num of packet lost (wrong seq num) of other data (non hdlc) */ + guint32 other_data_max_burst_lost; /* max burst num of packet lost (wrong seq num) of other data (non hdlc) */ + guint32 other_data_burst_lost; /* burst num of packet lost (wrong seq num) of other data (non hdlc) */ + gint32 start_frame_other_data; /* start frame of other_data */ + double start_time_other_data; /* start time of other_data */ + SEQ_STATUS prev_seq_status; /*previous seq num status used to calclate the busrt error */ + +} tap_t38_stat_t; + +/* structure that holds general information about the connection +* and structures for both directions */ +typedef struct _user_data_t { + /* tap associated data*/ + address ip_src_fwd; + guint16 port_src_fwd; + address ip_dst_fwd; + guint16 port_dst_fwd; + address ip_src_rev; + guint16 port_src_rev; + address ip_dst_rev; + guint16 port_dst_rev; + + tap_t38_stat_t forward; + tap_t38_stat_t reverse; + + graph_analysis_data_t *graph_analysis_data; +} user_data_t; + + + + + +/****************************************************************************/ +/* Add a new item into the graph */ +int add_to_graph_t38(user_data_t *user_data, packet_info *pinfo, const gchar *frame_label, gchar *comment, gint line_style) +{ + graph_analysis_item_t *gai; + + gai = g_malloc(sizeof(graph_analysis_item_t)); + gai->frame_num = pinfo->fd->num; + gai->time= nstime_to_sec(&pinfo->fd->rel_ts); + COPY_ADDRESS(&(gai->src_addr),&(pinfo->src)); + COPY_ADDRESS(&(gai->dst_addr),&(pinfo->dst)); + + gai->port_src=pinfo->srcport; + gai->port_dst=pinfo->destport; + if (frame_label != NULL) + gai->frame_label = g_strdup(frame_label); + else + gai->frame_label = g_strdup(""); + + if (comment != NULL) + gai->comment = g_strdup(comment); + else + gai->comment = g_strdup(""); + gai->conv_num=1; + gai->line_style=line_style; /* 1=single line 2=dual line */ + gai->display=TRUE; + + user_data->graph_analysis_data->graph_info->list = g_list_append(user_data->graph_analysis_data->graph_info->list, gai); + + return 1; +} + +/****************************************************************************/ +/* Change the frame_label and comment in a graph item if not NULL*/ +/* return 0 if the frame_num is not in the graph list */ +int change_frame_graph_t38(user_data_t *user_data, gint32 frame_num, const gchar *new_frame_label, const gchar *new_comment) +{ + graph_analysis_item_t *gai; + GList* list; + gchar *tmp_str = NULL; + gchar *tmp_str2 = NULL; + + if (frame_num == -1) return 0; + + list = g_list_first(user_data->graph_analysis_data->graph_info->list); + while (list) + { + gai = list->data; + if (gai->frame_num == (guint32) frame_num){ + tmp_str = gai->frame_label; + tmp_str2 = gai->comment; + + if (new_frame_label != NULL){ + gai->frame_label = g_strdup(new_frame_label); + g_free(tmp_str); + } + + if (new_comment != NULL){ + gai->comment = g_strdup(new_comment); + g_free(tmp_str2); + } + break; + } + list = g_list_next (list); + } + if (tmp_str == NULL) return 0; /* it is not in the list */ + return 1; +} + +/* TODO: Dissect the complete t30 HDLC packets */ +#if 0 +#define MAX_DESC 1024 +void dissect_t30_DIS_DTC(guint8 *data, guint len) +{ + guint8 octet; + int offset; + gchar buf[MAX_DESC]; + + offset = 3; + + if (len == 0) + return; + octet = data[offset]; + + g_snprintf(buf, MAX_DESC, "%sStore and forward Internet fax- Simple mode (ITU-T T.37)", octet&0x80?"":"No "); + + g_snprintf(buf, MAX_DESC, "%sReal-time Internet fax (ITU T T.38)", octet&0x20?"":"No "); + + g_snprintf(buf, MAX_DESC, "%s3rd Generation Mobile Network ", octet&0x10?"":"No ") +} +#endif + +/****************************************************************************/ +static const value_string t30_facsimile_control_field_vals_short[] = { + { 0x01, "DIS" }, + { 0x02, "CSI" }, + { 0x04, "NSF" }, + { 0x81, "DTC" }, + { 0x82, "CIG" }, + { 0x84, "NSC" }, + { 0x83, "PWD" }, + { 0x85, "SEP" }, + { 0x86, "PSA" }, + { 0x87, "CIA" }, + { 0x88, "ISP" }, + { 0x41, "DCS" }, + { 0x42, "TSI" }, + { 0x44, "NSS" }, + { 0x43, "SUB" }, + { 0x45, "SID" }, + { 0x46, "TSA" }, + { 0x47, "IRA" }, + { 0x21, "CFR" }, + { 0x22, "FTT" }, + { 0x24, "CSA" }, + { 0x71, "EOM" }, + { 0x72, "MPS" }, + { 0x74, "EOP" }, + { 0x79, "PRI-EOM" }, + { 0x7A, "PRI-MPS" }, + { 0x7C, "PRI-EOP" }, + { 0x78, "PRI-EOP" }, + { 0x31, "MCF" }, + { 0x33, "RTP" }, + { 0x32, "RTN" }, + { 0x35, "PIP" }, + { 0x34, "PIN" }, + { 0x3F, "FDM" }, + { 0x5F, "DCN" }, + { 0x58, "CRP" }, + { 0x53, "FNV" }, + { 0x57, "TNR" }, + { 0x56, "TR" } +}; + +static const value_string t30_facsimile_control_field_vals[] = { + { 0x01, "Digital Identification Signal" }, + { 0x02, "Called Subscriber Identification" }, + { 0x04, "Non-Standard Facilities" }, + { 0x81, "Digital Transmit Command" }, + { 0x82, "Calling Subscriber Identification" }, + { 0x84, "Non-Standard facilities Command" }, + { 0x83, "Password" }, + { 0x85, "Selective Polling" }, + { 0x86, "Polled Subaddress" }, + { 0x87, "Calling subscriber Internet Address" }, + { 0x88, "Internet Selective Polling Address" }, + { 0x41, "Digital Command Signal" }, + { 0x42, "Transmitting Subscriber Identification" }, + { 0x44, "Non-Standard facilities Set-up" }, + { 0x43, "Subaddress" }, + { 0x45, "Sender Identification" }, + { 0x46, "Transmitting Subscriber Internet address" }, + { 0x47, "Internet Routing Address" }, + { 0x21, "Confirmation To Receive" }, + { 0x22, "Failure To Train" }, + { 0x24, "Called Subscriber Internet Address" }, + { 0x71, "End Of Message" }, + { 0x72, "MultiPage Signal" }, + { 0x74, "End Of Procedure" }, + { 0x79, "Procedure Interrupt-End Of Message" }, + { 0x7A, "Procedure Interrupt-MultiPage Signal" }, + { 0x7C, "Procedure Interrupt-End Of Procedure" }, + { 0x78, "Procedure Interrupt-End Of Procedure" }, + { 0x31, "Message Confirmation" }, + { 0x33, "Retrain Positive" }, + { 0x32, "Retrain Negative" }, + { 0x35, "Procedure Interrupt Positive" }, + { 0x34, "Procedure Interrupt Negative" }, + { 0x3F, "File Diagnostics Message" }, + { 0x5F, "Disconnect" }, + { 0x58, "Command Repeat" }, + { 0x53, "Field Not Valid" }, + { 0x57, "Transmit not ready" }, + { 0x56, "Transmit ready" } + +}; + +static const value_string data_vals[] = { + { 0, "v21" }, + { 1, "v27-2400" }, + { 2, "v27-4800" }, + { 3, "v29-7200" }, + { 4, "v29-9600" }, + { 5, "v17-7200" }, + { 6, "v17-9600" }, + { 7, "v17-12000" }, + { 8, "v17-14400" }, + { 9, "v8" }, + { 10, "v34-pri-rate" }, + { 11, "v34-CC-1200" }, + { 12, "v34-pri-ch" }, + { 13, "v33-12000" }, + { 14, "v33-14400" }, + { 0, NULL }, +}; + +void dissect_t30(tap_t38_stat_t *statinfo, + user_data_t *user_data _U_, + packet_info *pinfo, + guint32 data_value +) +{ + gchar *frame_label = NULL; + gchar *comment = NULL; + guint8 octet; + + octet = statinfo->hdlc_data[2]; + +/* TODO: Dissect the complete t30 HDLC packets */ +#if 0 + /* Facsimile Control Field (FCF) */ + if ( ((octet&0xF0) == 0x00) || ((octet&0xF0) == 0x80) ) { /* Initial identification or Command to send */ + frame_label = g_strdup_printf("%s:hdlc:%s", val_to_str(data_value, data_vals, "Ukn (0x%02X)"), val_to_str(octet, t30_facsimile_control_field_vals_short, "Ukn (0x%02X)")); + comment = g_strdup_printf("%s:HDLC:%s",val_to_str(data_value, data_vals, "Ukn (0x%02X)"), val_to_str(octet, t30_facsimile_control_field_vals, "Ukn (0x%02X)")); + if ( (octet == 0x01) || (octet == 0x81) ) { + dissect_t30_DIS_DTC(statinfo->hdlc_data, statinfo->hdlc_data_index); + } + } else { /* all other values */ + frame_label = g_strdup_printf("%s:hdlc:%s", val_to_str(data_value, data_vals, "Ukn (0x%02X)"), val_to_str(octet&0x7F, t30_facsimile_control_field_vals_short, "Ukn (0x%02X)")); + comment = g_strdup_printf("%s:HDLC:%s",val_to_str(data_value, data_vals, "Ukn (0x%02X)"), val_to_str(octet&0x7F, t30_facsimile_control_field_vals, "Ukn (0x%02X)")); + } +#else + frame_label = g_strdup_printf("%s:hdlc:%s", val_to_str(data_value, data_vals, "Ukn (0x%02X)"), val_to_str(octet&0x7F, t30_facsimile_control_field_vals_short, "Ukn (0x%02X)")); + comment = g_strdup_printf("%s:HDLC:%s",val_to_str(data_value, data_vals, "Ukn (0x%02X)"), val_to_str(octet&0x7F, t30_facsimile_control_field_vals, "Ukn (0x%02X)")); +#endif + add_to_graph_t38(user_data, pinfo, frame_label, comment, 2); +} + +/****************************************************************************/ +int t38_packet_analyse(tap_t38_stat_t *statinfo, + user_data_t *user_data _U_, + packet_info *pinfo, + const t38_packet_info *t38_info) +{ + gchar *frame_label = NULL; + gchar *comment = NULL; + SEQ_STATUS seq_status = UNKNOWN; + + /* if it is duplicated, just return */ + if (statinfo->seq_num == t38_info->seq_num) return 0; + + /* if it is the correct seq or first packet */ + if ( (statinfo->seq_num+1 == t38_info->seq_num) || (statinfo->seq_num == -1) ) seq_status = CORRECT; + + /* EARLY: seq_num > than expexted */ + else if (t38_info->seq_num > statinfo->seq_num+1 ) seq_status = EARLY; + + /* LATE: seq_num < than expexted */ + else if (t38_info->seq_num < statinfo->seq_num+1 ) seq_status = LATE; + + + if (t38_info->type_msg == 0) { /* t30-indicator */ + frame_label = g_strdup_printf("t30 Ind:%s",val_to_str(t38_info->t30ind_value, t30_indicator_vals, "Ukn (0x%02X)") ); + comment = g_strdup_printf("t30 Ind:%s",val_to_str(t38_info->t30ind_value, t30_indicator_vals, "Ukn (0x%02X)") ); + add_to_graph_t38(user_data, pinfo, frame_label, comment, 1); + + /* reset other_data stats in case we never got the previos t4-non-ecm-sig-end */ + statinfo->other_data_num_bytes = 0; + statinfo->other_data_lost = 0; + statinfo->start_frame_other_data = -1; + statinfo->prev_seq_status = CORRECT; + statinfo->other_data_max_burst_lost = 0; + statinfo->other_data_burst_lost = 0; + statinfo->start_time_other_data = 0; + } else if (t38_info->type_msg == 1) { /* data */ + int i; + for (i=0; i<t38_info->t38_info_data_item_index; i++) { + switch(t38_info->data_type[i]){ + case 0: /* hdlc-data */ + /* if it is hdlc-data add it to the array */ + /* check we'll not excede the array */ + if (statinfo->hdlc_data_index+t38_info->data_len[i] < MAX_HDLC_FRAME) { + g_memmove(&statinfo->hdlc_data[statinfo->hdlc_data_index], t38_info->data[i],t38_info->data_len[i]); + statinfo->hdlc_data_index += t38_info->data_len[i]; + } + if (seq_status != CORRECT) statinfo->valid_hdlc_data = FALSE; + break; + case 2: /* hdlc-fcs-OK */ + case 4: /* hdlc-fcs-OK-sig-end */ + if (statinfo->valid_hdlc_data) + dissect_t30(statinfo, user_data, pinfo, t38_info->data_value); + else { + frame_label = g_strdup_printf("%s:hdlc:not decoded",val_to_str(t38_info->data_value, data_vals, "Ukn (0x%02X)")); + comment = g_strdup_printf("%s:HDLC:ERROR: wrong seq number in HDLC packet(s)",val_to_str(t38_info->data_value, data_vals, "Ukn (0x%02X)")); + add_to_graph_t38(user_data, pinfo, frame_label, comment, 2); + } + statinfo->hdlc_data_index = 0; + statinfo->valid_hdlc_data = TRUE; + break; + case 1: /* hdlc-sig-end */ + if (statinfo->hdlc_data_index != 0) { /* if there was no fcs-OK, this is an error */ + frame_label = g_strdup_printf("%s:hdlc:hdlc-sig-end",val_to_str(t38_info->data_value, data_vals, "Ukn (0x%02X)")); + comment = g_strdup_printf("%s:HDLC:ERROR: received hdlc-sig-end without received fcs-OK or fcs-BAD",val_to_str(t38_info->data_value, data_vals, "Ukn (0x%02X)")); + add_to_graph_t38(user_data, pinfo, frame_label, comment, 2); + statinfo->hdlc_data_index = 0; + } + break; + case 3: /* hdlc-fcs-BAD */ + case 5: /* hdlc-fcs-BAD-sig-end */ + frame_label = g_strdup_printf("%s:hdlc:%s",val_to_str(t38_info->data_value, data_vals, "Ukn (0x%02X)"),t38_info->data_type[i] == 3 ? "fcs-BAD" : "fcs-BAD-sig-end" ); + comment = g_strdup_printf("WARNING: received %s:hdlc:%s", val_to_str(t38_info->data_value, data_vals, "Ukn (0x%02X)"), t38_info->data_type[i] == 3 ? "fcs-BAD" : "fcs-BAD-sig-end"); + add_to_graph_t38(user_data, pinfo, frame_label, comment, 2); + statinfo->hdlc_data_index = 0; + break; + } + if ( (t38_info->data_type[i] == 6) || (t38_info->data_type[i] == 7) ) { /* t4-non-ecm-data or t4-non-ecm-sig-end */ + statinfo->other_data_num_bytes += t38_info->data_len[i]; + if (seq_status != CORRECT) { + statinfo->other_data_lost++; + statinfo->other_data_burst_lost++; + } else { + if (statinfo->other_data_burst_lost > statinfo->other_data_max_burst_lost) + statinfo->other_data_max_burst_lost = statinfo->other_data_burst_lost; + statinfo->other_data_burst_lost = 0; + } + if (statinfo->start_frame_other_data == -1) { + statinfo->start_frame_other_data = pinfo->fd->num; + statinfo->start_time_other_data = nstime_to_sec(&pinfo->fd->rel_ts); + } + + frame_label = g_strdup_printf("data:%s",val_to_str(t38_info->data_value, data_vals, "Ukn (0x%02X)") ); + comment = g_strdup_printf("Num of bytes: %d Duration: %.2fs Wrong seq num: %d Burst pack lost: %d", + statinfo->other_data_num_bytes, + nstime_to_sec(&pinfo->fd->rel_ts) - statinfo->start_time_other_data, + statinfo->other_data_lost, + statinfo->other_data_max_burst_lost); + if ( !change_frame_graph_t38(user_data, statinfo->start_frame_other_data, frame_label, comment) ) + add_to_graph_t38(user_data, pinfo, frame_label, comment, 2); + + if (t38_info->data_type[i] == 7) { /* t4-non-ecm-sig-end reset values */ + statinfo->other_data_num_bytes = 0; + statinfo->other_data_lost = 0; + statinfo->start_frame_other_data = -1; + statinfo->prev_seq_status = CORRECT; + statinfo->other_data_max_burst_lost = 0; + statinfo->other_data_burst_lost = 0; + } + } + } + } + if (seq_status != LATE) statinfo->seq_num = t38_info->seq_num; + g_free(frame_label); + g_free(comment); + return 0; +} + +/****************************************************************************/ +/* whenever a T38 packet is seen by the tap listener */ +static int t38_packet(void *user_data_arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *t38_info_arg) +{ + user_data_t *user_data = user_data_arg; + const t38_packet_info *t38_info = t38_info_arg; + /* we ignore packets that are not displayed */ + if (pinfo->fd->flags.passed_dfilter == 0) + return 0; + /* is it the forward direction? */ + else if (CMP_ADDRESS(&(user_data->ip_src_fwd), &(pinfo->net_src)) == 0 + && user_data->port_src_fwd == pinfo->srcport + && CMP_ADDRESS(&(user_data->ip_dst_fwd), &(pinfo->net_dst)) == 0 + && user_data->port_dst_fwd == pinfo->destport) { + t38_packet_analyse(&(user_data->forward),user_data, pinfo, t38_info); + } + /* is it the reversed direction? */ + else if (CMP_ADDRESS(&(user_data->ip_src_rev), &(pinfo->net_src)) == 0 + && user_data->port_src_rev == pinfo->srcport + && CMP_ADDRESS(&(user_data->ip_dst_rev), &(pinfo->net_dst)) == 0 + && user_data->port_dst_rev == pinfo->destport) { + t38_packet_analyse(&(user_data->reverse),user_data, pinfo, t38_info); + } + + return 1; +} + +/****************************************************************************/ +/* reset user_data valueas and clean graph info */ +static void +t38_clean(user_data_t *user_data) +{ + graph_analysis_item_t *gai; + GList* list; + + user_data->forward.hdlc_data_index = 0; + user_data->reverse.hdlc_data_index = 0; + + user_data->forward.wrong_seq_num = 0; + user_data->reverse.wrong_seq_num = 0; + + user_data->forward.seq_num = -1; + user_data->reverse.seq_num = -1; + + user_data->forward.valid_hdlc_data = TRUE; + user_data->reverse.valid_hdlc_data = TRUE; + + user_data->forward.other_data_num_bytes = 0; + user_data->reverse.other_data_num_bytes = 0; + + user_data->forward.other_data_lost = 0; + user_data->reverse.other_data_lost = 0; + + user_data->forward.other_data_max_burst_lost = 0; + user_data->reverse.other_data_max_burst_lost = 0; + + user_data->forward.other_data_burst_lost = 0; + user_data->reverse.other_data_burst_lost = 0; + + user_data->forward.start_frame_other_data = -1; + user_data->reverse.start_frame_other_data = -1; + + user_data->forward.start_time_other_data = 0; + user_data->reverse.start_time_other_data = 0; + + user_data->forward.prev_seq_status = CORRECT; + user_data->reverse.prev_seq_status = CORRECT; + + /* free the graph list */ + list = g_list_first(user_data->graph_analysis_data->graph_info->list); + while (list) + { + gai = list->data; + g_free(gai->frame_label); + g_free(gai->comment); + g_free((void *)gai->src_addr.data); + g_free((void *)gai->dst_addr.data); + g_free(list->data); + list = g_list_next (list); + } + g_list_free(user_data->graph_analysis_data->graph_info->list); + user_data->graph_analysis_data->graph_info->nconv = 0; + user_data->graph_analysis_data->graph_info->list = NULL; + + return; +} + + +/****************************************************************************/ +/* when there is a [re]reading of packet's */ +static void +t38_reset(void *user_data_arg) +{ + user_data_t *user_data = user_data_arg; + + t38_clean(user_data); + + /* create or refresh the graph windows */ + if (user_data->graph_analysis_data->dlg.window == NULL) /* create the window */ + graph_analysis_create(user_data->graph_analysis_data); + else + graph_analysis_update(user_data->graph_analysis_data); /* refresh it */ + + return; +} + +/****************************************************************************/ +static void +t38_draw(void *user_data_arg) +{ + user_data_t *user_data = user_data_arg; + + graph_analysis_redraw(user_data->graph_analysis_data); + + return; +} + +/****************************************************************************/ +/* called when the graph windows is destroyed */ +static void +t38_on_destroy(void *user_data_arg) +{ + user_data_t *user_data = user_data_arg; + + /* remove tap listener */ + protect_thread_critical_region(); + remove_tap_listener(user_data); + unprotect_thread_critical_region(); + + /* free the address */ + g_free((void *)user_data->ip_src_fwd.data); + g_free((void *)user_data->ip_dst_fwd.data); + g_free((void *)user_data->ip_src_rev.data); + g_free((void *)user_data->ip_dst_rev.data); + + /* clean graph info */ + t38_clean(user_data); + + g_free(user_data->graph_analysis_data->graph_info); + +} + +/****************************************************************************/ +void t38_analysis( + address *ip_src_fwd, + guint16 port_src_fwd, + address *ip_dst_fwd, + guint16 port_dst_fwd, + address *ip_src_rev, + guint16 port_src_rev, + address *ip_dst_rev, + guint16 port_dst_rev + ) +{ + user_data_t *user_data; + GString *error_string; + + /* init */ + user_data = g_malloc(sizeof(user_data_t)); + + user_data->graph_analysis_data = graph_analysis_init(); + user_data->graph_analysis_data->graph_info = g_malloc(sizeof(graph_analysis_info_t)); + user_data->graph_analysis_data->graph_info->nconv = 0; + user_data->graph_analysis_data->graph_info->list = NULL; + + user_data->graph_analysis_data->dlg.title = g_strdup("Fax T38 analysis"); + + user_data->graph_analysis_data->dlg.inverse = TRUE; /* to display "calling ----> called" fax call */ + + user_data->graph_analysis_data->on_destroy_user_data = t38_on_destroy; + user_data->graph_analysis_data->data = user_data; + + COPY_ADDRESS(&(user_data->ip_src_fwd), ip_src_fwd); + user_data->port_src_fwd = port_src_fwd; + COPY_ADDRESS(&(user_data->ip_dst_fwd), ip_dst_fwd); + user_data->port_dst_fwd = port_dst_fwd; + COPY_ADDRESS(&(user_data->ip_src_rev), ip_src_rev); + user_data->port_src_rev = port_src_rev; + COPY_ADDRESS(&(user_data->ip_dst_rev), ip_dst_rev); + user_data->port_dst_rev = port_dst_rev; + + /* register tap listener */ + error_string = register_tap_listener("t38", user_data, NULL, + t38_reset, t38_packet, t38_draw); + if (error_string != NULL) { + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, error_string->str); + g_string_free(error_string, TRUE); + return; + } + + /* retap all packets */ + cf_retap_packets(&cfile, FALSE); +} + +/****************************************************************************/ +/* entry point from main menu */ +void t38_analysis_cb(GtkWidget *w _U_, gpointer data _U_) +{ + address ip_src_fwd; + guint16 port_src_fwd; + address ip_dst_fwd; + guint16 port_dst_fwd; + address ip_src_rev; + guint16 port_src_rev; + address ip_dst_rev; + guint16 port_dst_rev; + + gchar filter_text[256]; + dfilter_t *sfcode; + capture_file *cf; + epan_dissect_t *edt; + gint err; + gchar *err_info; + gboolean frame_matched; + frame_data *fdata; + + /* Try to compile the filter. */ + strcpy(filter_text,"t38 && (ip || ipv6)"); + if (!dfilter_compile(filter_text, &sfcode)) { + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, dfilter_error_msg); + return; + } + /* we load the current file into cf variable */ + cf = &cfile; + fdata = cf->current_frame; + + /* we are on the selected frame now */ + if (fdata == NULL) + return; /* if we exit here it's an error */ + + /* dissect the current frame */ + if (!wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header, + cf->pd, fdata->cap_len, &err, &err_info)) { + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, + cf_read_error_message(err, err_info), cf->filename); + return; + } + edt = epan_dissect_new(TRUE, FALSE); + epan_dissect_prime_dfilter(edt, sfcode); + epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL); + frame_matched = dfilter_apply_edt(sfcode, edt); + + /* check if it is a t38 frame */ + frame_matched = dfilter_apply_edt(sfcode, edt); + if (frame_matched != 1) { + epan_dissect_free(edt); + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, + "You didn't choose a T38 packet!"); + return; + } + + /* ok, it is a T38 frame, so let's get the ip and port values */ + COPY_ADDRESS(&(ip_src_fwd), &(edt->pi.src)) + COPY_ADDRESS(&(ip_dst_fwd), &(edt->pi.dst)) + port_src_fwd = edt->pi.srcport; + port_dst_fwd = edt->pi.destport; + + /* assume the inverse ip/port combination for the reverse direction */ + COPY_ADDRESS(&(ip_src_rev), &(edt->pi.dst)) + COPY_ADDRESS(&(ip_dst_rev), &(edt->pi.src)) + port_src_rev = edt->pi.destport; + port_dst_rev = edt->pi.srcport; + + t38_analysis( + &ip_src_fwd, + port_src_fwd, + &ip_dst_fwd, + port_dst_fwd, + &ip_src_rev, + port_src_rev, + &ip_dst_rev, + port_dst_rev + ); + +} + +/****************************************************************************/ +static void +t38_analysis_init(char *dummy _U_) +{ + t38_analysis_cb(NULL, NULL); +} + +/****************************************************************************/ +void +register_tap_listener_t38_analysis(void) +{ + register_stat_cmd_arg("t38", t38_analysis_init); + + + register_stat_menu_item("Fax T38 Analysis...", REGISTER_STAT_GROUP_TELEPHONY, + t38_analysis_cb, NULL, NULL, NULL); +} Index: epan/libethereal.def =================================================================== --- epan/libethereal.def (revision 16065) +++ epan/libethereal.def (working copy) @@ -557,6 +557,7 @@ stats_tree_tick_pivot stats_tree_tick_range string_to_name_resolve +t30_indicator_vals DATA T_h323_message_body_vals DATA tap_push_tapped_queue tap_queue_init Index: epan/dissectors/packet-t38.c =================================================================== --- epan/dissectors/packet-t38.c (revision 16065) +++ epan/dissectors/packet-t38.c (working copy) @@ -51,6 +51,7 @@ #include <glib.h> #include <epan/packet.h> #include <epan/conversation.h> +#include <epan/tap.h> #include <stdio.h> #include <string.h> @@ -67,6 +68,8 @@ static guint global_t38_tcp_port = PORT_T38; static guint global_t38_udp_port = PORT_T38; +static int t38_tap = -1; + /* * Variables to allow for proper deletion of dissector registration when * the user changes port from the gui. @@ -171,6 +174,13 @@ /* Preferences bool to control whether or not setup info should be shown */ static gboolean global_t38_show_setup_info = TRUE; +/* Can tap up to 4 T38 packets within same packet */ +/* We only tap the primary part, not the redundancy */ +#define MAX_T38_MESSAGES_IN_PACKET 4 +static t38_packet_info t38_info_arr[MAX_T38_MESSAGES_IN_PACKET]; +static int t38_info_current=0; +static t38_packet_info *t38_info=NULL; + /* Set up an T38 conversation */ void t38_add_address(packet_info *pinfo, address *addr, int port, @@ -292,7 +302,7 @@ { 0, NULL, 0, NULL } }; -static const value_string t30_indicator_vals[] = { +const value_string t30_indicator_vals[] = { { 0, "no-signal" }, { 1, "cng" }, { 2, "ced" }, @@ -330,6 +340,11 @@ col_append_fstr(pinfo->cinfo, COL_INFO, " t30ind: %s", val_to_str(T30ind_value,t30_indicator_vals,"<unknown>")); } + + /* info for tap */ + if (primary_part) + t38_info->t30ind_value = T30ind_value; + return offset; } @@ -397,6 +412,12 @@ col_append_fstr(pinfo->cinfo, COL_INFO, " data:%s:", val_to_str(Data_value,data_vals,"<unknown>")); } + + + /* info for tap */ + if (primary_part) + t38_info->data_value = Data_value; + return offset; } @@ -419,6 +440,10 @@ ett_t38_Type_of_msg, Type_of_msg_choice, &Type_of_msg_value); + /* info for tap */ + if (primary_part) + t38_info->type_msg = Type_of_msg_value; + return offset; } @@ -511,6 +536,16 @@ val_to_str(Data_Field_field_type_value,Data_Field_field_type_vals,"<unknown>")); } + /* info for tap */ + if (primary_part) { + if ( (t38_info->t38_info_data_item_index < MAX_T38_DATA_ITEMS) && (t38_info->t38_info_data_item_index >= 0) ){ /*sanity check */ + t38_info->data_type[t38_info->t38_info_data_item_index] = Data_Field_field_type_value; + + if (t38_info->t38_info_data_item_index++ == MAX_T38_DATA_ITEMS-1) t38_info->t38_info_data_item_index = 1; + } + } + + return offset; } @@ -535,6 +570,16 @@ tvb_bytes_to_str(value_tvb,0,7)); } } + + + /* info for tap */ + if (primary_part) { + if ( (t38_info->t38_info_data_item_index <= MAX_T38_DATA_ITEMS) && (t38_info->t38_info_data_item_index > 0) ){ /*sanity check */ + t38_info->data_len[t38_info->t38_info_data_item_index-1] = value_len; + t38_info->data[t38_info->t38_info_data_item_index-1] = tvb_memdup(value_tvb,0,value_len); + } + } + return offset; } @@ -591,6 +636,10 @@ offset=dissect_per_constrained_integer(tvb, offset, pinfo, tree, hf_t38_seq_number, 0, 65535, &seq_number, NULL, FALSE); + + /* info for tap */ + if (primary_part) + t38_info->seq_num = seq_number; if (check_col(pinfo->cinfo, COL_INFO)){ col_append_fstr(pinfo->cinfo, COL_INFO, "Seq=%05u ",seq_number); @@ -630,7 +679,8 @@ { /* When the field-data is not present, we MUST offset 1 byte*/ if((Data_Field_field_type_value != 0) && - (Data_Field_field_type_value != 6)) + (Data_Field_field_type_value != 6) && + (Data_Field_field_type_value != 7)) { offset=offset+8; } @@ -745,6 +795,7 @@ proto_item *it; proto_tree *tr; guint32 offset=0; + int i; /* * XXX - heuristic to check for misidentified packets. @@ -757,6 +808,25 @@ } } + /* tap info */ + t38_info_current++; + if (t38_info_current==MAX_T38_MESSAGES_IN_PACKET) { + t38_info_current=0; + } + t38_info = &t38_info_arr[t38_info_current]; + + t38_info->seq_num = 0; + t38_info->type_msg = 0; + t38_info->data_value = 0; + t38_info->t30ind_value =0; + + t38_info->t38_info_data_item_index = 0; + for (i=0; i<MAX_T38_DATA_ITEMS; i++) { + t38_info->data_type[i] = 0; + t38_info->data[i] = NULL; + t38_info->data_len[i] = 0; + } + if (check_col(pinfo->cinfo, COL_PROTOCOL)){ col_set_str(pinfo->cinfo, COL_PROTOCOL, "T.38"); } @@ -794,6 +864,18 @@ col_append_fstr(pinfo->cinfo, COL_INFO, " [Malformed?]"); } } + + /* if is a valid t38 packet, add to tap */ + if (!pinfo->in_error_pkt) + tap_queue_packet(t38_tap, pinfo, t38_info); + else { /* if not, free the data */ + for (i=0; i<MAX_T38_DATA_ITEMS; i++) { + t38_info->data_type[i] = 0; + g_free(t38_info->data[i]); + t38_info->data[i] = NULL; + t38_info->data_len[i] = 0; + } + } } static void @@ -1037,6 +1119,8 @@ proto_register_subtree_array(ett, array_length(ett)); register_dissector("t38", dissect_t38, proto_t38); + t38_tap = register_tap("t38"); + t38_module = prefs_register_protocol(proto_t38, proto_reg_handoff_t38); prefs_register_bool_preference(t38_module, "use_pre_corrigendum_asn1_specification", "Use the Pre-Corrigendum ASN.1 specification", Index: epan/dissectors/packet-t38.h =================================================================== --- epan/dissectors/packet-t38.h (revision 16065) +++ epan/dissectors/packet-t38.h (working copy) @@ -25,6 +25,20 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#define MAX_T38_DATA_ITEMS 4 +typedef struct _t38_packet_info { + guint16 seq_num; /* UDPTLPacket sequence number */ + guint32 type_msg; /* 0=t30-indicator 1=data */ + guint32 t30ind_value; + guint32 data_value; /* standard and speed */ + + int t38_info_data_item_index; /* this will have the number of Data Items in the packet and is used as the index when decoding the packet */ + guint32 data_type[MAX_T38_DATA_ITEMS]; + guint8 *data[MAX_T38_DATA_ITEMS]; + gint data_len[MAX_T38_DATA_ITEMS]; +} t38_packet_info; + + /* Info to save in T38 conversation / packet-info */ #define MAX_T38_SETUP_METHOD_SIZE 7 struct _t38_conversation_info @@ -37,4 +51,6 @@ void t38_add_address(packet_info *pinfo, address *addr, int port, int other_port, - const gchar *setup_method, guint32 setup_frame_number); + gchar *setup_method, guint32 setup_frame_number); + +ETH_VAR_IMPORT const value_string t30_indicator_vals[];
- Follow-Ups:
- Re: [Ethereal-dev] Fax t38 Analysis
- From: Andreas Sikkema
- SV: [Ethereal-dev] Fax t38 Analysis
- From: Anders Broman
- Re: [Ethereal-dev] Fax t38 Analysis
- From: Guy Harris
- Re: [Ethereal-dev] Fax t38 Analysis
- Prev by Date: Re: [Ethereal-dev] Problem with upgrading Win32 packages
- Next by Date: Re: [Ethereal-dev] Fax t38 Analysis
- Previous by thread: Re: [Ethereal-dev] Problem with upgrading Win32 packages
- Next by thread: Re: [Ethereal-dev] Fax t38 Analysis
- Index(es):