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):






