Ethereal-dev: [Ethereal-dev] AudioCodes trunk trace protocol (ISDN and CAS)
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, 26 Jun 2005 16:24:57 -0600
Hi All,Attached is a new dissector for the AudioCodes trunk trace protocol. This protocol is used to debug the trunk protocol in AudioCodes gateways. It currently supports ISDN PRI and CAS (MFCR2, WinkStart, etc...) trunk protocols. It also add these protocols in the "Voip Calls Graph..." (attached is screenshot of a SIP to ISDN call in the "Voip graph..")
Regards Alejandro
Index: gtk/voip_calls_dlg.c =================================================================== --- gtk/voip_calls_dlg.c (revision 14788) +++ gtk/voip_calls_dlg.c (working copy) @@ -55,7 +55,6 @@ #include "ui_util.h" #include "compat_macros.h" #include "gtkglobals.h" -#include "webbrowser.h" #include "image/clist_ascend.xpm" #include "image/clist_descend.xpm" @@ -126,8 +125,8 @@ switch(strinfo->protocol){ case VOIP_ISUP: tmp_isupinfo = strinfo->prot_info; - g_snprintf(field[8],30, "%i-%i -> %i-%i. CIC: %i", tmp_isupinfo->ni, tmp_isupinfo->opc, - tmp_isupinfo->ni, tmp_isupinfo->dpc, tmp_isupinfo->cic); + g_snprintf(field[8],30, "%i-%i -> %i-%i", tmp_isupinfo->ni, tmp_isupinfo->opc, + tmp_isupinfo->ni, tmp_isupinfo->dpc); break; case VOIP_H323: tmp_h323info = strinfo->prot_info; @@ -184,6 +183,7 @@ if (find_tap_id("mgcp")) { remove_tap_listener_mgcp_calls(); } + remove_tap_listener_actrace_calls(); } /****************************************************************************/ @@ -335,13 +335,6 @@ /****************************************************************************/ - -static void help_bt_clicked( GtkButton *button _U_) -{ - browser_open_url("http://wiki.ethereal.com/VoIP_20calls"); -} - - static void on_graph_bt_clicked (GtkButton *button _U_, gpointer user_data _U_) @@ -534,7 +527,6 @@ GtkWidget *scrolledwindow; GtkWidget *hbuttonbox; GtkWidget *bt_close; - GtkWidget *bt_help; GtkTooltips *tooltips = gtk_tooltips_new(); gchar *titles[NUM_COLS] = {"Start Time", "Stop Time", "Initial Speaker", "From", "To", "Protocol", "Packets", "State", "Comments"}; @@ -623,11 +615,6 @@ gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox), GTK_BUTTONBOX_SPREAD); gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbuttonbox), 30); - bt_help = BUTTON_NEW_FROM_STOCK(GTK_STOCK_HELP); - gtk_container_add (GTK_CONTAINER (hbuttonbox), bt_help); - SIGNAL_CONNECT(bt_help, "clicked", help_bt_clicked, NULL); - gtk_tooltips_set_tip (tooltips, bt_help, "Go to the help page", NULL); - /*bt_unselect = gtk_button_new_with_label ("Unselect"); gtk_container_add (GTK_CONTAINER (hbuttonbox), bt_unselect); gtk_tooltips_set_tip (tooltips, bt_unselect, "Unselect this conversation", NULL);*/ @@ -638,6 +625,7 @@ bt_graph = gtk_button_new_with_label("Graph"); gtk_container_add(GTK_CONTAINER(hbuttonbox), bt_graph); + gtk_widget_show(bt_graph); SIGNAL_CONNECT(bt_graph, "clicked", on_graph_bt_clicked, NULL); gtk_tooltips_set_tip (tooltips, bt_graph, "Show a flow graph of the selected calls.", NULL); @@ -748,6 +736,7 @@ if (find_tap_id("mgcp")) { mgcp_calls_init_tap(); } + actrace_calls_init_tap(); /* init the Graph Analysys */ graph_analysis_data = graph_analysis_init(); Index: gtk/voip_calls.c =================================================================== --- gtk/voip_calls.c (revision 14788) +++ gtk/voip_calls.c (working copy) @@ -10,7 +10,7 @@ * Copyright 2004, Iskratel, Ltd, Kranj * By Miha Jemec <m.jemec@xxxxxxxxxxx> * - * H323, RTP, RTP Event, MGCP and Graph Support + * H323, RTP, RTP Event, MGCP, AudioCodes (ISDN PRI and CAS) and Graph Support * By Alejandro Vaquero, alejandro.vaquero@xxxxxxxxx * Copyright 2005, Verso Technologies Inc. * @@ -54,6 +54,7 @@ #include <epan/dissectors/packet-q931.h> #include <epan/dissectors/packet-sdp.h> #include <plugins/mgcp/packet-mgcp.h> +#include <epan/dissectors/packet-actrace.h> #include <epan/dissectors/packet-rtp.h> #include <epan/dissectors/packet-rtp-events.h> #include <epan/conversation.h> @@ -73,11 +74,13 @@ }; /* defines whether we can consider the call active */ -char *voip_protocol_name[4]={ +char *voip_protocol_name[6]={ "SIP", "ISUP", "H323", - "MGCP" + "MGCP", + "AC_ISDN", + "AC_CAS" }; typedef struct { @@ -98,7 +101,7 @@ /****************************************************************************/ /* the one and only global voip_calls_tapinfo_t structure */ static voip_calls_tapinfo_t the_tapinfo_struct = - {0, NULL, 0, NULL, 0, 0, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0, 0}; + {0, NULL, 0, NULL, 0, 0, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* the one and only global voip_rtp_tapinfo_t structure */ static voip_rtp_tapinfo_t the_tapinfo_rtp_struct = @@ -187,15 +190,18 @@ /****************************************************************************/ /* 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) +int add_to_graph(voip_calls_tapinfo_t *tapinfo _U_, packet_info *pinfo, gchar *frame_label, gchar *comment, guint16 call_num, address *src_addr, address *dst_addr) { graph_analysis_item_t *gai; gai = g_malloc(sizeof(graph_analysis_item_t)); gai->frame_num = pinfo->fd->num; gai->time= (double)pinfo->fd->rel_secs + (double) pinfo->fd->rel_usecs/1000000; - COPY_ADDRESS(&(gai->src_addr),&(pinfo->src)); - COPY_ADDRESS(&(gai->dst_addr),&(pinfo->dst)); +/* COPY_ADDRESS(&(gai->src_addr),&(pinfo->src)); + COPY_ADDRESS(&(gai->dst_addr),&(pinfo->dst));*/ + COPY_ADDRESS(&(gai->src_addr),src_addr); + COPY_ADDRESS(&(gai->dst_addr),dst_addr); + gai->port_src=pinfo->srcport; gai->port_dst=pinfo->destport; if (frame_label != NULL) @@ -731,7 +737,7 @@ ++(tapinfo->npackets); /* add to the graph */ - add_to_graph(tapinfo, pinfo, frame_label, comment, strinfo->call_num); + add_to_graph(tapinfo, pinfo, frame_label, comment, strinfo->call_num, &(pinfo->src), &(pinfo->dst)); g_free(comment); g_free(frame_label); g_free((void *)tmp_src.data); @@ -980,7 +986,7 @@ ++(tapinfo->npackets); /* add to the graph */ - add_to_graph(tapinfo, pinfo, frame_label, comment, strinfo->call_num); + add_to_graph(tapinfo, pinfo, frame_label, comment, strinfo->call_num, &(pinfo->src), &(pinfo->dst)); g_free(comment); g_free(frame_label); } @@ -1115,6 +1121,11 @@ static h225_cs_type h225_cstype = H225_OTHER; static gboolean h225_is_faststart; +static guint32 actrace_frame_num = 0; +static gint32 actrace_trunk = 0; +static gint32 actrace_direction = 0; + + /****************************************************************************/ /* whenever a q931_ packet is seen by the tap listener */ static int @@ -1123,6 +1134,7 @@ GList *list,*list2; voip_calls_tapinfo_t *tapinfo = &the_tapinfo_struct; h323_calls_info_t *tmp_h323info,*tmp2_h323info; + actrace_isdn_calls_info_t *tmp_actrace_isdn_info; voip_calls_info_t *tmp_listinfo; voip_calls_info_t *strinfo = NULL; h245_address_t *h245_add = NULL; @@ -1242,6 +1254,8 @@ /* we reset the h225_frame_num to 0 because there could be empty h225 in the same frame as non empty h225 (e.g connect), so we don't have to be here twice */ h225_frame_num = 0; + + /* add staff to H245 */ } else if (h245_labels.frame_num == q931_frame_num) { /* there are empty H225 frames that don't have guid (guaid=0) but they have h245 info, so the only way to match those frames is with the Q931 CRV number */ @@ -1258,7 +1272,7 @@ /* if the frame number exists in graph, append to it*/ if (!append_to_frame_graph(tapinfo, q931_frame_num, "", comment)) { /* if not exist, add to the graph */ - add_to_graph(tapinfo, pinfo, "", comment, tmp_listinfo->call_num); + add_to_graph(tapinfo, pinfo, "", comment, tmp_listinfo->call_num, &(pinfo->src), &(pinfo->dst)); } /* Add the H245 info if exists to the Graph */ @@ -1269,7 +1283,103 @@ } list = g_list_next (list); } + + /* add staff to ACTRACE */ + } else if (actrace_frame_num == q931_frame_num) { + address pstn_add; + gchar *comment = NULL; + + strinfo = NULL; + list = g_list_first(tapinfo->strinfo_list); + while (list) + { + tmp_listinfo=list->data; + if ( tmp_listinfo->protocol == VOIP_AC_ISDN ){ + tmp_actrace_isdn_info = tmp_listinfo->prot_info; + /* TODO: Also check the IP of the Blade, and if the call is complete (no active) */ + if ( (tmp_actrace_isdn_info->crv == q931_crv) && (tmp_actrace_isdn_info->trunk == actrace_trunk) ) { + strinfo = (voip_calls_info_t*)(list->data); + break; + } + } + list = g_list_next (list); + } + + pstn_add.type = AT_STRINGZ; + pstn_add.len = 5; + pstn_add.data = g_strdup("PSTN"); + + /* if it is a new call, add it to the list */ + if (!strinfo) { + strinfo = g_malloc(sizeof(voip_calls_info_t)); + strinfo->call_active_state = VOIP_ACTIVE; + strinfo->call_state = VOIP_CALL_SETUP; + strinfo->from_identity=g_strdup(q931_calling_number); + strinfo->to_identity=g_strdup(q931_called_number); + COPY_ADDRESS(&(strinfo->initial_speaker),actrace_direction?&pstn_add:&(pinfo->src)); + strinfo->first_frame_num=pinfo->fd->num; + strinfo->selected=FALSE; + strinfo->start_sec=pinfo->fd->rel_secs; + strinfo->start_usec=pinfo->fd->rel_usecs; + strinfo->protocol=VOIP_AC_ISDN; + strinfo->prot_info=g_malloc(sizeof(actrace_isdn_calls_info_t)); + tmp_actrace_isdn_info=strinfo->prot_info; + tmp_actrace_isdn_info->crv=q931_crv; + tmp_actrace_isdn_info->trunk=actrace_trunk; + strinfo->npackets = 0; + strinfo->call_num = tapinfo->ncalls++; + tapinfo->strinfo_list = g_list_append(tapinfo->strinfo_list, strinfo); + } + + strinfo->stop_sec=pinfo->fd->rel_secs; + strinfo->stop_usec=pinfo->fd->rel_usecs; + strinfo->last_frame_num=pinfo->fd->num; + ++(strinfo->npackets); + /* increment the packets counter of all calls */ + ++(tapinfo->npackets); + + switch(pi->message_type){ + case Q931_SETUP: + comment = g_strdup_printf("AC_ISDN trunk:%u Calling: %s Called:%s", actrace_trunk, q931_calling_number, q931_called_number); + strinfo->call_state=VOIP_CALL_SETUP; + break; + case Q931_CONNECT: + strinfo->call_state=VOIP_IN_CALL; + break; + case Q931_RELEASE_COMPLETE: + case Q931_RELEASE: + case Q931_DISCONNECT: + if (strinfo->call_state==VOIP_CALL_SETUP){ + if (ADDRESSES_EQUAL(&(strinfo->initial_speaker), actrace_direction?&pstn_add:&(pinfo->src) )){ /* forward direction */ + strinfo->call_state=VOIP_CANCELLED; + } + else{ /* reverse */ + strinfo->call_state=VOIP_REJECTED; + tapinfo->rejected_calls++; + } + } else if ( (strinfo->call_state!=VOIP_CANCELLED) && (strinfo->call_state!=VOIP_REJECTED) ){ + strinfo->call_state=VOIP_COMPLETED; + tapinfo->completed_calls++; + } + if (q931_cause_value != 0xFF){ + comment = g_strdup_printf("AC_ISDN trunk:%u Q931 Rel Cause (%i):%s", actrace_trunk, q931_cause_value, val_to_str(q931_cause_value, q931_cause_code_vals, "<unknown>")); + } else { /* Cause not set */ + comment = g_strdup("AC_ISDN No Q931 Rel Cause"); + } + break; + } + + if (!comment) + comment = g_strdup_printf("AC_ISDN trunk:%u", actrace_trunk ); + + add_to_graph(tapinfo, pinfo, val_to_str(pi->message_type, q931_message_type_vals, "<unknown>") , comment, strinfo->call_num, + actrace_direction?&pstn_add:&(pinfo->src), + actrace_direction?&(pinfo->src):&pstn_add); + + g_free(comment); + g_free((char *)pstn_add.data); } + return 0; } @@ -1529,7 +1639,7 @@ /* if the frame number exists in graph, append to it*/ if (!append_to_frame_graph(tapinfo, pinfo->fd->num, pi->frame_label, comment)) { /* if not exist, add to the graph */ - add_to_graph(tapinfo, pinfo, frame_label, comment, strinfo->call_num); + add_to_graph(tapinfo, pinfo, frame_label, comment, strinfo->call_num, &(pinfo->src), &(pinfo->dst)); g_free((void *)tmp_src.data); g_free((void *)tmp_dst.data); } @@ -1699,7 +1809,7 @@ /* if the frame number exists in graph, append to it*/ if (!append_to_frame_graph(tapinfo, pinfo->fd->num, frame_label, comment)) { /* if not exist, add to the graph */ - add_to_graph(tapinfo, pinfo, frame_label, comment, strinfo->call_num); + add_to_graph(tapinfo, pinfo, frame_label, comment, strinfo->call_num, &(pinfo->src), &(pinfo->dst)); } g_free(frame_label); g_free(comment); @@ -2136,7 +2246,7 @@ ++(tapinfo->npackets); /* add to the graph */ - add_to_graph(tapinfo, pinfo, frame_label, comment, strinfo->call_num); + add_to_graph(tapinfo, pinfo, frame_label, comment, strinfo->call_num, &(pinfo->src), &(pinfo->dst)); g_free(comment); g_free(frame_label); @@ -2198,8 +2308,139 @@ } +/****************************************************************************/ +/****************************TAP for ACTRACE (AudioCodes trace)**************/ +/****************************************************************************/ +/* whenever a ACTRACE packet is seen by the tap listener */ +static int +ACTRACEcalls_packet(void *ptr _U_, packet_info *pinfo, epan_dissect_t *edt _U_, const void *ACTRACEinfo) +{ + voip_calls_tapinfo_t *tapinfo = &the_tapinfo_struct; + const actrace_info_t *pi = ACTRACEinfo; + GList *list; + actrace_cas_calls_info_t *tmp_actrace_cas_info; + voip_calls_info_t *tmp_listinfo; + voip_calls_info_t *strinfo = NULL; + + + actrace_frame_num = pinfo->fd->num; + actrace_trunk = pi->trunk; + actrace_direction = pi->direction; + + if (pi->type == 1){ /* is CAS protocol */ + address pstn_add; + gchar *comment = NULL; + + strinfo = NULL; + list = g_list_first(tapinfo->strinfo_list); + while (list) + { + tmp_listinfo=list->data; + if ( tmp_listinfo->protocol == VOIP_AC_CAS ){ + tmp_actrace_cas_info = tmp_listinfo->prot_info; + /* TODO: Also check the IP of the Blade, and if the call is complete (no active) */ + if ( (tmp_actrace_cas_info->bchannel == pi->cas_bchannel) && (tmp_actrace_cas_info->trunk == actrace_trunk) ) { + strinfo = (voip_calls_info_t*)(list->data); + break; + } + } + list = g_list_next (list); + } + + pstn_add.type = AT_STRINGZ; + pstn_add.len = 5; + pstn_add.data = g_strdup("PSTN"); + + /* if it is a new call, add it to the list */ + if (!strinfo) { + strinfo = g_malloc(sizeof(voip_calls_info_t)); + strinfo->call_active_state = VOIP_ACTIVE; + strinfo->call_state = VOIP_CALL_SETUP; + strinfo->from_identity=g_strdup("N/A"); + strinfo->to_identity=g_strdup("N/A"); + COPY_ADDRESS(&(strinfo->initial_speaker),actrace_direction?&pstn_add:&(pinfo->src)); + strinfo->first_frame_num=pinfo->fd->num; + strinfo->selected=FALSE; + strinfo->start_sec=pinfo->fd->rel_secs; + strinfo->start_usec=pinfo->fd->rel_usecs; + strinfo->protocol=VOIP_AC_CAS; + strinfo->prot_info=g_malloc(sizeof(actrace_cas_calls_info_t)); + tmp_actrace_cas_info=strinfo->prot_info; + tmp_actrace_cas_info->bchannel=pi->cas_bchannel; + tmp_actrace_cas_info->trunk=actrace_trunk; + strinfo->npackets = 0; + strinfo->call_num = tapinfo->ncalls++; + tapinfo->strinfo_list = g_list_append(tapinfo->strinfo_list, strinfo); + } + + strinfo->stop_sec=pinfo->fd->rel_secs; + strinfo->stop_usec=pinfo->fd->rel_usecs; + strinfo->last_frame_num=pinfo->fd->num; + ++(strinfo->npackets); + /* increment the packets counter of all calls */ + ++(tapinfo->npackets); + + if (!comment) + comment = g_strdup_printf("AC_CAS trunk:%u", actrace_trunk ); + + add_to_graph(tapinfo, pinfo, pi->cas_frame_label , comment, strinfo->call_num, + actrace_direction?&pstn_add:&(pinfo->src), + actrace_direction?&(pinfo->src):&pstn_add); + + g_free(comment); + g_free((char *)pstn_add.data); + } + return 1; /* refresh output */ +} + + /****************************************************************************/ +/* TAP INTERFACE */ +/****************************************************************************/ +static gboolean have_actrace_tap_listener=FALSE; +/****************************************************************************/ +void +actrace_calls_init_tap(void) +{ + GString *error_string; + + if(have_actrace_tap_listener==FALSE) + { + /* don't register tap listener, if we have it already */ + error_string = register_tap_listener("actrace", &(the_tapinfo_struct.actrace_dummy), NULL, + voip_calls_dlg_reset, + ACTRACEcalls_packet, + voip_calls_dlg_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_actrace_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_actrace_calls(void) +{ + protect_thread_critical_region(); + remove_tap_listener(&(the_tapinfo_struct.actrace_dummy)); + unprotect_thread_critical_region(); + + have_actrace_tap_listener=FALSE; +} + +/****************************************************************************/ /* ***************************TAP for OTHER PROTOCOL **********************************/ /****************************************************************************/ Index: gtk/voip_calls.h =================================================================== --- gtk/voip_calls.h (revision 14788) +++ gtk/voip_calls.h (working copy) @@ -63,10 +63,12 @@ VOIP_SIP, VOIP_ISUP, VOIP_H323, - VOIP_MGCP + VOIP_MGCP, + VOIP_AC_ISDN, + VOIP_AC_CAS } voip_protocol; -extern char *voip_protocol_name[4]; +extern char *voip_protocol_name[6]; /* defines specific SIP data */ @@ -115,7 +117,18 @@ gboolean fromEndpoint; /* true if the call was originated from the Endpoint, false for calls from MGC */ } mgcp_calls_info_t; +/* defines specific ACTRACE ISDN data */ +typedef struct _actrace_isdn_calls_info { + gint32 crv; + int trunk; +} actrace_isdn_calls_info_t; +/* defines specific ACTRACE CAS data */ +typedef struct _actrace_cas_calls_info { + gint32 bchannel; + int trunk; +} actrace_cas_calls_info_t; + /* defines a voip call */ typedef struct _voip_calls_info { voip_call_state call_state; @@ -159,6 +172,7 @@ int isup_dummy; int q931_dummy; int mgcp_dummy; + int actrace_dummy; } voip_calls_tapinfo_t; @@ -213,8 +227,8 @@ void rtp_init_tap(void); void rtp_event_init_tap(void); void mgcp_calls_init_tap(void); +void actrace_calls_init_tap(void); - /* * Removes the voip_calls tap listener (if not already done) * From that point on, the voip calls list won't be updated any more. @@ -229,6 +243,7 @@ void remove_tap_listener_rtp(void); void remove_tap_listener_rtp_event(void); void remove_tap_listener_mgcp_calls(void); +void remove_tap_listener_actrace_calls(void); /* * Retrieves a constant reference to the unique info structure of the voip_calls tap listener. Index: epan/libethereal.def =================================================================== --- epan/libethereal.def (revision 14788) +++ epan/libethereal.def (working copy) @@ -454,6 +454,7 @@ p_get_proto_data q931_cause_code_vals DATA q850_cause_code_vals DATA +q931_message_type_vals DATA range_convert_range range_convert_str range_copy Index: epan/dissectors/packet-actrace.c =================================================================== --- epan/dissectors/packet-actrace.c (revision 0) +++ epan/dissectors/packet-actrace.c (revision 0) @@ -0,0 +1,873 @@ +/* packet-actrace.c + * Routines for AudioCodes Trunk traces packet disassembly + * + * Copyright (c) 2005 by Alejandro Vaquero <alejandro.vaquero@xxxxxxxxx> + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@xxxxxxxxxxxx> + * Copyright 1999 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <ctype.h> +#include <string.h> +#include <epan/packet.h> +#include <epan/proto.h> +#include <epan/prefs.h> +#include <epan/conversation.h> +#include <epan/tap.h> +#include "packet-actrace.h" + +#define UDP_PORT_ACTRACE 2428 +#define ACTRACE_CAS 1 +#define ACTRACE_ISDN 2 + + +void proto_reg_handoff_actrace(void); + + +/* Define the actrace proto */ +static int proto_actrace = -1; + +/* Define many headers for actrace */ +/* ISDN headers */ +static int hf_actrace_isdn_direction = -1; +static int hf_actrace_isdn_trunk = -1; +static int hf_actrace_isdn_length = -1; + + +/* CAS headers */ +static int hf_actrace_cas_time = -1; +static int hf_actrace_cas_source = -1; +static int hf_actrace_cas_current_state = -1; +static int hf_actrace_cas_event = -1; +static int hf_actrace_cas_next_state = -1; +static int hf_actrace_cas_function = -1; +static int hf_actrace_cas_par0 = -1; +static int hf_actrace_cas_par1 = -1; +static int hf_actrace_cas_par2 = -1; +static int hf_actrace_cas_trunk = -1; +static int hf_actrace_cas_bchannel = -1; +static int hf_actrace_cas_connection_id = -1; + + + +static dissector_handle_t lapd_handle; + +#define ACTRACE_CAS_SOURCE_DSP 0 +#define ACTRACE_CAS_SOURCE_USER 1 +#define ACTRACE_CAS_SOURCE_TABLE 2 + +static const value_string actrace_cas_source_vals[] = { + {ACTRACE_CAS_SOURCE_DSP, "DSP"}, + {ACTRACE_CAS_SOURCE_USER, "User"}, + {ACTRACE_CAS_SOURCE_TABLE, "Table"}, + {0, NULL } +}; + +static const value_string actrace_cas_source_vals_short[] = { + {ACTRACE_CAS_SOURCE_DSP, "D"}, + {ACTRACE_CAS_SOURCE_USER, "U"}, + {ACTRACE_CAS_SOURCE_TABLE, "T"}, + {0, NULL } +}; + +#define ACTRACE_CAS_EV_11 17 +#define ACTRACE_CAS_EV_10 18 +#define ACTRACE_CAS_EV_01 19 +#define ACTRACE_CAS_EV_00 20 + +#define ACTRACE_CAS_EV_DTMF 302 +#define ACTRACE_CAS_EV_FIRST_DIGIT 63 + +static const value_string actrace_cas_event_ab_vals[] = { + {ACTRACE_CAS_EV_11, "11"}, + {ACTRACE_CAS_EV_10, "10"}, + {ACTRACE_CAS_EV_01, "01"}, + {ACTRACE_CAS_EV_00, "00"} +}; + +static const value_string actrace_cas_mf_vals[] = { + {32, "1"}, + {33, "2"}, + {34, "3"}, + {35, "4"}, + {36, "5"}, + {37, "6"}, + {38, "7"}, + {39, "8"}, + {40, "9"}, + {41, "0"}, + {42, "A"}, + {43, "B"}, + {44, "C"}, + {45, "*"}, + {46, "#"} +}; + +static const value_string actrace_cas_event_vals[] = { + {0, "FUNCTION0"}, + {1, "FUNCTION1"}, + {2, "FUNCTION2"}, + {3, "FUNCTION3"}, + {4, "EV_PLACE_CALL"}, + {5, "EV_TIMER_EXPIRED1"}, + {6, "EV_TIMER_EXPIRED2"}, + {7, "EV_TIMER_EXPIRED3"}, + {8, "EV_TIMER_EXPIRED4"}, + {9, "EV_TIMER_EXPIRED5"}, + {10, "EV_TIMER_EXPIRED6"}, + {11, "EV_TIMER_EXPIRED7"}, + {12, "EV_TIMER_EXPIRED8"}, + {13, "EV_ANSWER"}, + {14, "EV_DIAL_TONE_DETECTED"}, + {15, "EV_DIAL_ENDED"}, + {16, "EV_DISCONNECT"}, + {ACTRACE_CAS_EV_11, "EV_CAS_1_1"}, + {ACTRACE_CAS_EV_10, "EV_CAS_1_0"}, + {ACTRACE_CAS_EV_01, "EV_CAS_0_1"}, + {ACTRACE_CAS_EV_00, "EV_CAS_0_0"}, + {21, "EV_RB_TONE_STARTED"}, + {22, "EV_RB_TONE_STOPPED"}, + {23, "EV_BUSY_TONE"}, + {24, "EV_FAST_BUSY_TONE"}, + {25, "EV_HELLO_DETECTED"}, + {26, "EV_DIAL_TONE_STOPPED"}, + {27, "EV_DISCONNECT_INCOMING"}, + {28, "EV_RELEASE_CALL"}, + {29, "EV_DIALED_NUM_DETECTED"}, + {30, "EV_COUNTER1_EXPIRED"}, + {31, "EV_COUNTER2_EXPIRED"}, + {32, "EV_MFRn_1"}, + {33, "EV_MFRn_2"}, + {34, "EV_MFRn_3"}, + {35, "EV_MFRn_4"}, + {36, "EV_MFRn_5"}, + {37, "EV_MFRn_6"}, + {38, "EV_MFRn_7"}, + {39, "EV_MFRn_8"}, + {40, "EV_MFRn_9"}, + {41, "EV_MFRn_10"}, + {42, "EV_MFRn_11"}, + {43, "EV_MFRn_12"}, + {44, "EV_MFRn_13"}, + {45, "EV_MFRn_14"}, + {46, "EV_MFRn_15"}, + {47, "EV_MFRn_1_STOPED"}, + {48, "EV_MFRn_2_STOPED"}, + {49, "EV_MFRn_3_STOPED"}, + {50, "EV_MFRn_4_STOPED"}, + {51, "EV_MFRn_5_STOPED"}, + {52, "EV_MFRn_6_STOPED"}, + {53, "EV_MFRn_7_STOPED"}, + {54, "EV_MFRn_8_STOPED"}, + {55, "EV_MFRn_9_STOPED"}, + {56, "EV_MFRn_10_STOPED"}, + {57, "EV_MFRn_11_STOPED"}, + {58, "EV_MFRn_12_STOPED"}, + {59, "EV_MFRn_13_STOPED"}, + {60, "EV_MFRn_14_STOPED"}, + {61, "EV_MFRn_15_STOPED"}, + {62, "EV_ANI_NUM_DETECTED"}, + {ACTRACE_CAS_EV_FIRST_DIGIT, "EV_FIRST_DIGIT"}, + {64, "EV_END_OF_MF_DIGIT"}, + {65, "EV_ACCEPT"}, + {66, "EV_REJECT_BUSY"}, + {67, "EV_REJECT_CONGESTION"}, + {68, "EV_REJECT_UNALLOCATED"}, + {69, "EV_REJECT_RESERVE1"}, + {70, "EV_REJECT_RESERVE2"}, + {71, "EV_NO_ANI"}, + {1010, "EV_TIMER_EXPIRED10"}, + {1020, "EV_DEBOUNCE_TIMER_EXPIRED"}, + {1030, "EV_INTER_DIGIT_TIMER_EXPIRED"}, + {100, "EV_INIT_CHANNEL"}, + {101, "EV_BUSY_TONE_STOPPED"}, + {102, "EV_FAST_BUSY_TONE_STOPPED"}, + {103, "EV_TO_USER"}, + {104, "SEND_FIRST_DIGIT"}, + {110, "EV_CLOSE_CHANNEL"}, + {111, "EV_OPEN_CHANNEL"}, + {112, "EV_FAIL_DIAL"}, + {113, "EV_FAIL_SEND_CAS"}, + {114, "EV_ALARM"}, + {ACTRACE_CAS_EV_DTMF, "EV_DTMF"}, +}; + +#define SEND_CAS 2 +#define SEND_EVENT 3 +#define CHANGE_COLLECT_TYPE 13 +#define SEND_MF 8 +#define SEND_DEST_NUM 4 + +static const value_string actrace_cas_function_vals[] = { + {0, "NILL"}, + {1, "SET_TIMER"}, + {SEND_CAS, "SEND_CAS"}, + {SEND_EVENT, "SEND_EVENT"}, + {SEND_DEST_NUM, "SEND_DEST_NUM"}, + {5, "DEL_TIMER"}, + {6, "START_COLLECT"}, + {7, "STOP_COLLECT"}, + {SEND_MF, "SEND_MF"}, + {9, "STOP_DIAL_MF"}, + {10, "SET_COUNTER"}, + {11, "DEC_COUNTER"}, + {12, "SEND_PROG_TON"}, + {CHANGE_COLLECT_TYPE, "CHANGE_COLLECT_TYPE"}, + {14, "GENERATE_CAS_EV"} +}; + +static const value_string actrace_cas_pstn_event_vals[] = { + {64, "acEV_PSTN_INTERNAL_ERROR"}, + {65, "acEV_PSTN_CALL_CONNECTED"}, + {66, "acEV_PSTN_INCOMING_CALL_DETECTED"}, + {67, "acEV_PSTN_CALL_DISCONNECTED"}, + {68, "acEV_PSTN_CALL_RELEASED"}, + {69, "acEV_PSTN_REMOTE_ALERTING"}, + {70, "acEV_PSTN_STARTED"}, + {71, "acEV_PSTN_WARNING"}, + {72, "acEV_ISDN_PROGRESS_INDICATION"}, + {73, "acEV_PSTN_PROCEEDING_INDICATION"}, + {74, "acEV_PSTN_ALARM"}, + {75, "acEV_RESERVED"}, + {76, "acEV_PSTN_LINE_INFO"}, + {77, "acEV_PSTN_LOOP_CONFIRM"}, + {78, "acEV_PSTN_RESTART_CONFIRM"}, + {84, "acEV_ISDN_SETUP_ACK_IN"}, + {85, "acEV_PSTN_CALL_INFORMATION"}, + {128, "acEV_CAS_SEIZURE_DETECTED"}, + {129, "acEV_CAS_CHANNEL_BLOCKED"}, + {130, "acEV_CAS_PROTOCOL_STARTED"}, + {131, "acEV_PSTN_CALL_STATE_RESPONSE"}, + {132, "acEV_CAS_SEIZURE_ACK"} +}; + +static const value_string actrace_cas_collect_type_vals[] = { + {0, "COLLECT_TYPE_ADDRESS"}, + {1, "COLLECT_TYPE_ANI"}, + {2, "COLLECT_TYPE_SOURCE_CATEGORY"}, + {3, "COLLECT_TYPE_LINE_CATEGORY"}, +}; + +#define SEND_TYPE_ADDRESS 1 +#define SEND_TYPE_SPECIFIC 2 +#define SEND_TYPE_INTER_EXCHANGE_SWITCH 3 +#define SEND_TYPE_ANI 4 +#define SEND_TYPE_SOURCE_CATEGORY 5 +#define SEND_TYPE_TRANSFER_CAPABILITY 6 + +static const value_string actrace_cas_send_type_vals[] = { + {SEND_TYPE_ADDRESS, "ADDRESS"}, + {SEND_TYPE_SPECIFIC, "SPECIFIC"}, + {SEND_TYPE_INTER_EXCHANGE_SWITCH, "INTER_EXCHANGE_SWITCH"}, + {SEND_TYPE_ANI, "ANI"}, + {SEND_TYPE_SOURCE_CATEGORY, "SOURCE_CATEGORY"}, + {SEND_TYPE_TRANSFER_CAPABILITY, "TRANSFER_CAPABILITY"}, +}; + +static const value_string actrace_cas_cause_vals[] = { + {1, "UNASSIGNED_NUMBER"}, + {2, "NO_ROUTE_TO_TRANSIT_NET"}, + {3, "NO_ROUTE_TO_DESTINATION"}, + {6, "CHANNEL_UNACCEPTABLE"}, + {7, "CALL_AWARDED_AND"}, + {8, "PREEMPTION"}, + {16, "NORMAL_CALL_CLEAR"}, + {17, "USER_BUSY"}, + {18, "NO_USER_RESPONDING"}, + {19, "NO_ANSWER_FROM_USER_ALERTED"}, + {20, "ACCEPT_DONE"}, + {21, "CALL_REJECTED"}, + {22, "NUMBER_CHANGED"}, + {26, "NON_SELECTED_USER_CLEARING"}, + {27, "DEST_OUT_OF_ORDER"}, + {28, "INVALID_NUMBER_FORMAT"}, + {29, "FACILITY_REJECT"}, + {30, "RESPONSE_TO_STATUS_ENQUIRY"}, + {31, "NORMAL_UNSPECIFIED"}, + {32, "CIRCUIT_CONGESTION"}, + {33, "USER_CONGESTION"}, + {34, "NO_CIRCUIT_AVAILABLE"}, + {38, "NETWORK_OUT_OF_ORDER"}, + {41, "NETWORK_TEMPORARY_FAILURE"}, + {42, "NETWORK_CONGESTION"}, + {43, "ACCESS_INFORMATION_DISCARDED"}, + {44, "REQUESTED_CIRCUIT_NOT_AVAILABLE"}, + {47, "RESOURCE_UNAVAILABLE_UNSPECIFIED"}, + {39, "PERM_FR_MODE_CONN_OUT_OF_S"}, + {40, "PERM_FR_MODE_CONN_OPERATIONAL"}, + {46, "PRECEDENCE_CALL_BLOCKED"}, + {49, "QUALITY_OF_SERVICE_UNAVAILABLE"}, + {50, "REQUESTED_FAC_NOT_SUBSCRIBED"}, + {57, "BC_NOT_AUTHORIZED"}, + {58, "BC_NOT_PRESENTLY_AVAILABLE"}, + {63, "SERVICE_NOT_AVAILABLE"}, + {53, "CUG_OUT_CALLS_BARRED"}, + {55, "CUG_INC_CALLS_BARRED"}, + {62, "ACCES_INFO_SUBS_CLASS_INCONS"}, + {65, "BC_NOT_IMPLEMENTED"}, + {66, "CHANNEL_TYPE_NOT_IMPLEMENTED"}, + {69, "REQUESTED_FAC_NOT_IMPLEMENTED"}, + {70, "ONLY_RESTRICTED_INFO_BEARER"}, + {79, "SERVICE_NOT_IMPLEMENTED_UNSPECIFIED"}, + {81, "INVALID_CALL_REF"}, + {82, "IDENTIFIED_CHANNEL_NOT_EXIST"}, + {83, "SUSPENDED_CALL_BUT_CALL_ID_NOT_EXIST"}, + {84, "CALL_ID_IN_USE"}, + {85, "NO_CALL_SUSPENDED"}, + {86, "CALL_HAVING_CALL_ID_CLEARED"}, + {88, "INCOMPATIBLE_DESTINATION"}, + {91, "INVALID_TRANSIT_NETWORK_SELECTION"}, + {95, "INVALID_MESSAGE_UNSPECIFIED"}, + {87, "NOT_CUG_MEMBER"}, + {90, "CUG_NON_EXISTENT"}, + {96, "MANDATORY_IE_MISSING"}, + {97, "MESSAGE_TYPE_NON_EXISTENT"}, + {98, "MESSAGE_STATE_INCONSISTENCY"}, + {99, "NON_EXISTENT_IE"}, + {100, "INVALID_IE_CONTENT"}, + {101, "MESSAGE_NOT_COMPATIBLE"}, + {102, "RECOVERY_ON_TIMER_EXPIRY"}, + {111, "PROTOCOL_ERROR_UNSPECIFIED"}, + {127, "INTERWORKING_UNSPECIFIED"}, + {128, "ACU_CAUSE_ACU_BAD_ADDRESS"}, + {129, "ACU_CAUSE_ACU_BAD_SERVICE"}, + {130, "ACU_CAUSE_ACU_COLLISION"}, + {131, "ACU_CAUSE_ACU_FAC_REJECTED"}, + {255, "ACU_NETWORK_CAUSE_NIL"}, + {200, "C_ALREADY_BLOCKED"}, + {201, "C_CHANNEL_BLOCKED"}, + {202, "C_BLOCKING_DONE"}, + {203, "C_ALREADY_UNBLOCKED"}, + {204, "C_UNBLOCKING_DONE"}, + {260, "CLRN_MFRn_A4"}, + {261, "CLRN_MFRn_B1"}, + {262, "CLRN_MFRn_B2"}, + {263, "CLRN_MFRn_B3"}, + {264, "CLRN_MFRn_B4"}, + {265, "CLRN_MFRn_B5"}, + {266, "CLRN_MFRn_B6"}, + {267, "CLRN_MFRn_B7"}, + {268, "CLRN_MFRn_B8"}, + {269, "CLRN_MFRn_B9"}, + {270, "CLRN_MFRn_B10"}, + {271, "CLRN_MFRn_B11"}, + {272, "CLRN_MFRn_B12"}, + {273, "CLRN_MFRn_B13"}, + {274, "CLRN_MFRn_B14"}, + {275, "CLRN_MFRn_B15"}, + {300, "ACURC_BUSY"}, + {301, "ACURC_NOPROCEED"}, + {302, "ACURC_NOANSWER"}, + {303, "ACURC_NOAUTOANSWER"}, + {304, "ACURC_CONGESTED"}, + {305, "ACURC_INCOMING"}, + {306, "ACURC_NOLINE"}, + {307, "ACURC_ERRNUM"}, + {308, "ACURC_INHNUM"}, + {309, "ACURC_2MNUM"}, + {310, "ACURC_HUNGUP"}, + {311, "ACURC_NETWORK_ERROR"}, + {312, "ACURC_TIMEOUT"}, + {313, "ACURC_BAD_SERVICE"}, + {314, "ACURC_INTERNAL"}, + {315, "ACURC_OK"}, + {316, "ACURC_BL_TIMEOUT"}, + {317, "ACURC_IN_CALL"}, + {318, "ACURC_CLEAR_RQ"}, +}; + +/* ISDN */ +#define PSTN_TO_BLADE 0x49446463 +#define BLADE_TO_PSTN 0x49644443 + +static const value_string actrace_isdn_direction_vals[] = { + {PSTN_TO_BLADE, "Blade <-- PSTN"}, + {BLADE_TO_PSTN, "Blade --> PSTN"}, +}; + +/* + * Define the trees for actrace + * We need one for actrace itself, and one for the trunk protocol (CAS, ISDN, SS7) + */ +static int ett_actrace = -1; +static int ett_actrace_proto = -1; + +/* + * Define the tap for actrace + */ +static int actrace_tap = -1; +static actrace_info_t *actrace_pi; + +/* + * Here are the global variable associated with + * the user definable characteristics of the dissection + */ +static int global_actrace_udp_port = UDP_PORT_ACTRACE; +static int global_actrace_protocol = ACTRACE_CAS; + +/* + * Variables to allow for proper deletion of dissector registration when + * the user changes port from the gui. + */ +static int actrace_udp_port = 0; + +/* Some basic utility functions that are specific to this dissector */ +static gboolean is_actrace(tvbuff_t *tvb, gint offset); + +/* + * The dissect functions + */ +static void dissect_actrace_cas(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + proto_tree *actrace_tree, proto_tree *ti); +static void dissect_actrace_isdn(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + proto_tree *actrace_tree, proto_tree *ti); + +/************************************************************************ + * dissect_actrace - The dissector for the AudioCodes Trace prtocol + ************************************************************************/ +static void dissect_actrace(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + gint sectionlen; + gint tvb_sectionend,tvb_sectionbegin, tvb_len, tvb_current_len; + proto_tree *actrace_tree, *ti; + + /* Initialize variables */ + tvb_sectionend = 0; + tvb_sectionbegin = tvb_sectionend; + sectionlen = 0; + tvb_len = tvb_length(tvb); + tvb_current_len = tvb_len; + actrace_tree = NULL; + ti = NULL; + + /* + * Set the columns now, so that they'll be set correctly if we throw + * an exception. We can set them later as well.... + */ + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + col_add_str(pinfo->cinfo, COL_PROTOCOL, "AC_TRACE"); + if (check_col(pinfo->cinfo, COL_INFO)) + col_clear(pinfo->cinfo, COL_INFO); + + /* + * Check to see whether we're really dealing with AC trace by looking + * for a valid "source" and fixed len for CAS; and the direction for ISDN. + * This isn't infallible, but its cheap and its better than nothing. + */ + if (is_actrace(tvb, 0)) + { + if (tree) + { + /* Create our actrace subtree */ + ti = proto_tree_add_item(tree,proto_actrace,tvb,0,-1, FALSE); + actrace_tree = proto_item_add_subtree(ti, ett_actrace); + } + + switch (global_actrace_protocol) + { + case ACTRACE_CAS: + dissect_actrace_cas(tvb, pinfo, tree, actrace_tree,ti); + break; + case ACTRACE_ISDN: + dissect_actrace_isdn(tvb, pinfo, tree, actrace_tree,ti); + break; + } + } else { + if (check_col(pinfo->cinfo, COL_INFO)) + col_add_str(pinfo->cinfo, COL_INFO, "Non CAS or ISDN AudioCodes trace message"); + } +} + +static actrace_info_t pi; + +/* Dissect an individual actrace CAS message */ +static void dissect_actrace_cas(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + proto_tree *actrace_tree, proto_tree *ti) +{ + /* Declare variables */ + gint sectionlen; + gint tvb_sectionend,tvb_sectionbegin, tvb_len, tvb_current_len; + gint32 value, function, trunk, bchannel, source, event, curr_state, next_state; + gint32 par0, par1, par2; + gchar *frame_label = NULL; + int direction = 0; + int offset = 0; + + /* Initialize variables */ + tvb_sectionend = 0; + tvb_sectionbegin = tvb_sectionend; + sectionlen = 0; + tvb_len = tvb_length(tvb); + tvb_current_len = tvb_len; + value = 0; + + /* the CAS masages are 48 byte fixed */ + if (tvb_len != 48) return; + + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + col_add_str(pinfo->cinfo, COL_PROTOCOL, "AC_CAS"); + + value = tvb_get_ntohl(tvb, offset); + proto_tree_add_int(actrace_tree, hf_actrace_cas_time, tvb, offset, 4, value); + offset += 4; + + source = tvb_get_ntohl(tvb, offset); + proto_tree_add_int(actrace_tree, hf_actrace_cas_source, tvb, offset, 4, source); + offset += 4; + + curr_state = tvb_get_ntohl(tvb, offset); + proto_tree_add_int(actrace_tree, hf_actrace_cas_current_state, tvb, offset, 4, curr_state); + offset += 4; + + event = tvb_get_ntohl(tvb, offset); + proto_tree_add_int(actrace_tree, hf_actrace_cas_event, tvb, offset, 4, event); + offset += 4; + + next_state = tvb_get_ntohl(tvb, offset); + proto_tree_add_int(actrace_tree, hf_actrace_cas_next_state, tvb, offset, 4, next_state); + offset += 4; + + function = tvb_get_ntohl(tvb, offset); + proto_tree_add_int(actrace_tree, hf_actrace_cas_function, tvb, offset, 4, function); + offset += 4; + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, "%s|%d|%s|%d|%s|", + val_to_str(source, actrace_cas_source_vals_short, "ukn"), + curr_state, + val_to_str(event, actrace_cas_event_vals, "%d"), + next_state, + val_to_str(function, actrace_cas_function_vals, "%d")); + + par0 = tvb_get_ntohl(tvb, offset); + switch (function) + { + case SEND_EVENT: + proto_tree_add_text(actrace_tree, tvb, offset, 4, + "Parameter 0: %s", val_to_str(par0, + actrace_cas_pstn_event_vals, "Unknown (%d)")); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, "%s|", + val_to_str(par0, actrace_cas_pstn_event_vals, "%d")); + break; + case CHANGE_COLLECT_TYPE: + proto_tree_add_text(actrace_tree, tvb, offset, 4, + "Parameter 0: %s", val_to_str(par0, + actrace_cas_collect_type_vals, "Unknown (%d)")); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, "%s|", + val_to_str(par0, actrace_cas_collect_type_vals, "%d")); + break; + case SEND_MF: + case SEND_DEST_NUM: + proto_tree_add_text(actrace_tree, tvb, offset, 4, + "Parameter 0: %s", val_to_str(par0, + actrace_cas_send_type_vals, "Unknown (%d)")); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, "%s|", + val_to_str(par0, actrace_cas_send_type_vals, "%d")); + break; + default: + proto_tree_add_int(actrace_tree, hf_actrace_cas_par0, tvb, offset, 4, par0); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, "%d|", par0); + } + offset += 4; + + par1 = tvb_get_ntohl(tvb, offset); + if (function == SEND_EVENT) { + proto_tree_add_text(actrace_tree, tvb, offset, 4, + "Parameter 1: %s", val_to_str(par1, actrace_cas_cause_vals, "Unknown (%d)")); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, "%s|", + val_to_str(par1, actrace_cas_cause_vals, "%d")); + } else { + proto_tree_add_int(actrace_tree, hf_actrace_cas_par1, tvb, offset, 4, par1); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, "%d|", par1); + } + offset += 4; + + par2 = tvb_get_ntohl(tvb, offset); + proto_tree_add_int(actrace_tree, hf_actrace_cas_par2, tvb, offset, 4, par2); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, "%d|", par2); + offset += 4; + + trunk = tvb_get_ntohl(tvb, offset); + proto_tree_add_int(actrace_tree, hf_actrace_cas_trunk, tvb, offset, 4, trunk); + offset += 4; + + bchannel = tvb_get_ntohl(tvb, offset); + proto_tree_add_int(actrace_tree, hf_actrace_cas_bchannel, tvb, offset, 4, bchannel); + offset += 4; + + if (check_col(pinfo->cinfo, COL_INFO)) + col_prepend_fstr(pinfo->cinfo, COL_INFO, "t%db%d|", trunk, bchannel); + + value = tvb_get_ntohl(tvb, offset); + proto_tree_add_int(actrace_tree, hf_actrace_cas_connection_id, tvb, offset, 4, value); + offset += 4; + + /* Add tap info for the Voip Graph */ + if (source == ACTRACE_CAS_SOURCE_DSP) { + direction = 1; + if ( (event >= ACTRACE_CAS_EV_11) && (event <= ACTRACE_CAS_EV_00 ) ) { + frame_label = g_strdup_printf("AB: %s", val_to_str(event, actrace_cas_event_ab_vals, "ERROR") ); + } else if ( (event >= 32) && (event <= 46 ) ) { /* is an MF tone */ + frame_label = g_strdup_printf("MF: %s", val_to_str(event, actrace_cas_mf_vals, "ERROR") ); + } else if ( (event == ACTRACE_CAS_EV_DTMF ) || (event == ACTRACE_CAS_EV_FIRST_DIGIT ) ) { /* DTMF digit */ + frame_label = g_strdup_printf("DTMF: %u", par0 ); + } + } else if (source == ACTRACE_CAS_SOURCE_TABLE) { + direction = 0; + if (function == SEND_MF) { + if (par0 == SEND_TYPE_SPECIFIC ) { + frame_label = g_strdup_printf("MF: %u", par1); + } else if (par0 == SEND_TYPE_ADDRESS ) { + frame_label = g_strdup("MF: DNIS digit"); + } else if (par0 == SEND_TYPE_ANI ) { + frame_label = g_strdup("MF: ANI digit"); + } else if (par0 == SEND_TYPE_SOURCE_CATEGORY ) { + frame_label = g_strdup("MF: src_category"); + } else if (par0 == SEND_TYPE_TRANSFER_CAPABILITY ) { + frame_label = g_strdup("MF: trf_capability"); + } else if (par0 == SEND_TYPE_INTER_EXCHANGE_SWITCH ) { + frame_label = g_strdup("MF: inter_exch_sw"); + } + } else if (function == SEND_CAS) { + frame_label = g_strdup_printf("AB: %s", val_to_str(ACTRACE_CAS_EV_00-par0, actrace_cas_event_ab_vals, "ERROR")); + } else if (function == SEND_DEST_NUM) { + if (par0 == SEND_TYPE_ADDRESS ) { + frame_label = g_strdup_printf("DTMF/MF: sending DNIS", par1); + } else if (par0 == SEND_TYPE_ANI ) { + frame_label = g_strdup("DTMF/MF: sending ANI"); + } + } + } + + if (frame_label != NULL) { + /* Initialise packet info for passing to tap */ + actrace_pi = g_malloc(sizeof(actrace_info_t)); + + actrace_pi->type = ACTRACE_CAS; + actrace_pi->direction = direction; + actrace_pi->trunk = trunk; + actrace_pi->cas_bchannel = bchannel; + actrace_pi->cas_frame_label = frame_label; + /* Report this packet to the tap */ + tap_queue_packet(actrace_tap, pinfo, actrace_pi); + } +} + +/* Dissect an individual actrace ISDN message */ +static void dissect_actrace_isdn(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + proto_tree *actrace_tree, proto_tree *ti) +{ + /* Declare variables */ + gint len; + gint32 value, trunk; + tvbuff_t *next_tvb; + int offset = 0; + + len = tvb_get_ntohs(tvb, 44); + + value = tvb_get_ntohl(tvb, offset+4); + proto_tree_add_int(actrace_tree, hf_actrace_isdn_direction, tvb, offset+4, 4, value); + + offset += 8; + trunk = tvb_get_ntohs(tvb, offset); + proto_tree_add_int(actrace_tree, hf_actrace_isdn_trunk, tvb, offset, 2, trunk); + + offset = 44; + proto_tree_add_int(actrace_tree, hf_actrace_isdn_length, tvb, offset, 2, len); + + + /* if it is a q931 packet (we don't want LAPD packets for Voip Graph) add tap info */ + if (len > 4) { + /* Initialise packet info for passing to tap */ + actrace_pi = g_malloc(sizeof(actrace_info_t)); + + actrace_pi->type = ACTRACE_ISDN; + actrace_pi->direction = (value==PSTN_TO_BLADE?1:0); + actrace_pi->trunk = trunk; + + /* Report this packet to the tap */ + tap_queue_packet(actrace_tap, pinfo, actrace_pi); + } + + /* Dissect lapd payload */ + offset += 2 ; + next_tvb = tvb_new_subset(tvb, offset, len, len); + call_dissector(lapd_handle, next_tvb, pinfo, tree); + + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + col_add_str(pinfo->cinfo, COL_PROTOCOL, "AC_ISDN"); + if (check_col(pinfo->cinfo, COL_INFO)) + col_prepend_fstr(pinfo->cinfo, COL_INFO, "Trunk:%d Blade %s PSTN " + , trunk, value==PSTN_TO_BLADE?"<--":"-->"); +} + +/* Register all the bits needed with the filtering engine */ +void proto_register_actrace(void) +{ + static hf_register_info hf[] = + { + /* CAS */ + { &hf_actrace_cas_time, + { "Time", "actrace.cas.time", FT_INT32, BASE_DEC, NULL, 0x0, + "Capture Time", HFILL }}, + { &hf_actrace_cas_source, + { "Source", "actrace.cas.source", FT_INT32, BASE_DEC, VALS(actrace_cas_source_vals), 0x0, + "Source", HFILL }}, + { &hf_actrace_cas_current_state, + { "Current State", "actrace.cas.curr_state", FT_INT32, BASE_DEC, NULL, 0x0, + "Current State", HFILL }}, + { &hf_actrace_cas_event, + { "Event", "actrace.cas.event", FT_INT32, BASE_DEC, VALS(actrace_cas_event_vals), 0x0, + "New Event", HFILL }}, + { &hf_actrace_cas_next_state, + { "Next State", "actrace.cas.next_state", FT_INT32, BASE_DEC, NULL, 0x0, + "Next State", HFILL }}, + { &hf_actrace_cas_function, + { "Function", "actrace.cas.function", FT_INT32, BASE_DEC, VALS(actrace_cas_function_vals), 0x0, + "Function", HFILL }}, + { &hf_actrace_cas_par0, + { "Parameter 0", "actrace.cas.par0", FT_INT32, BASE_DEC, NULL, 0x0, + "Parameter 0", HFILL }}, + { &hf_actrace_cas_par1, + { "Parameter 1", "actrace.cas.par1", FT_INT32, BASE_DEC, NULL, 0x0, + "Parameter 1", HFILL }}, + { &hf_actrace_cas_par2, + { "Parameter 2", "actrace.cas.par2", FT_INT32, BASE_DEC, NULL, 0x0, + "Parameter 2", HFILL }}, + { &hf_actrace_cas_trunk, + { "Trunk Number", "actrace.cas.trunk", FT_INT32, BASE_DEC, NULL, 0x0, + "Trunk Number", HFILL }}, + { &hf_actrace_cas_bchannel, + { "BChannel", "actrace.cas.bchannel", FT_INT32, BASE_DEC, NULL, 0x0, + "BChannel", HFILL }}, + { &hf_actrace_cas_connection_id, + { "Connection ID", "actrace.cas.conn_id", FT_INT32, BASE_DEC, NULL, 0x0, + "Connection ID", HFILL }}, + + /* ISDN */ + { &hf_actrace_isdn_trunk, + { "Trunk Number", "actrace.isdn.trunk", FT_INT16, BASE_DEC, NULL, 0x0, + "Trunk Number", HFILL }}, + { &hf_actrace_isdn_direction, + { "Direction", "actrace.isdn.dir", FT_INT32, BASE_DEC, VALS(actrace_isdn_direction_vals), 0x0, + "Direction", HFILL }}, + { &hf_actrace_isdn_length, + { "Length", "actrace.isdn.length", FT_INT16, BASE_DEC, NULL, 0x0, + "Length", HFILL }}, + }; + + static gint *ett[] = + { + &ett_actrace, + }; + + module_t *actrace_module; + + /* Register protocol */ + proto_actrace = proto_register_protocol("AudioCodes Trunk Trace", "ACtrace", "actrace"); + proto_register_field_array(proto_actrace, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + /* Register our configuration options */ + actrace_module = prefs_register_protocol(proto_actrace, proto_reg_handoff_actrace); + + prefs_register_uint_preference(actrace_module, "udp_port", + "AudioCodes Trunk Trace UDP port", + "Set the UDP port for AudioCodes Trunk Traces.\n" + "Use http://x.x.x.x/TrunkTraces to enable the traces in the Blade", + 10, &global_actrace_udp_port); + + prefs_register_obsolete_preference(actrace_module, "display_dissect_tree"); + + actrace_tap = register_tap("actrace"); +} + +/* The registration hand-off routine */ +void proto_reg_handoff_actrace(void) +{ + static int actrace_prefs_initialized = FALSE; + static dissector_handle_t actrace_handle; + + /* Get a handle for the lapd dissector. */ + lapd_handle = find_dissector("lapd"); + + if (!actrace_prefs_initialized) + { + actrace_handle = create_dissector_handle(dissect_actrace, proto_actrace); + actrace_prefs_initialized = TRUE; + } + else + { + dissector_delete("udp.port", actrace_udp_port, actrace_handle); + } + + /* Set our port number for future use */ + actrace_udp_port = global_actrace_udp_port; + + dissector_add("udp.port", global_actrace_udp_port, actrace_handle); +} + +/* + * is_actrace - A function for determining whether there is a + * AudioCodes packet at offset in tvb. The packet could be + * a CAS, ISDN or other Trunk protocol. Here we are only + * trying to decode CAS or ISDN protocols + * + * Parameter: + * tvb - The tvbuff in which we are looking for + * offset - The offset in tvb at which we are looking for + * + * Return: TRUE if there is an AudioCode trace packet at offset in tvb, otherwise FALSE + */ +static gboolean is_actrace(tvbuff_t *tvb, gint offset) +{ + gint tvb_len; + gint32 source, isdn_header; + + tvb_len = tvb_length(tvb); + + /* is a CAS packet? + * the CAS masages are 48 byte fixed and the sorce should be 0,1 or 2 (DSP, User or Table) + */ + source = tvb_get_ntohl(tvb, offset+4); + if ( (tvb_len == 48) && ((source > -1) && (source <3)) ) { + global_actrace_protocol = ACTRACE_CAS; + return TRUE; + } + /* is ISDN packet? + * the ISDN packets have 0x49446463 for packets from PSTN to the Blade and + * 0x49644443 for packets from the Blade to the PSTN at offset 4 + */ + isdn_header = tvb_get_ntohl(tvb, offset+4); + if ( (tvb_len >= 50) && ( (isdn_header == PSTN_TO_BLADE) || (isdn_header == BLADE_TO_PSTN)) ){ + global_actrace_protocol = ACTRACE_ISDN; + return TRUE; + } + return FALSE; +} \ No newline at end of file Index: epan/dissectors/packet-actrace.h =================================================================== --- epan/dissectors/packet-actrace.h (revision 0) +++ epan/dissectors/packet-actrace.h (revision 0) @@ -0,0 +1,35 @@ +/* packet-actrace.h + * Routines for AudioCodes Trunk traces packet disassembly + * + * + * Copyright (c) 2005 by Alejandro Vaquero <alejandro.vaquero@xxxxxxxxx> + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@xxxxxxxxxxxx> + * Copyright 1999 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Container for tapping relevant data */ +typedef struct _actrace_info_t +{ + int type; /* ACTRACE_CAS=1 ACTRACE_ISDN=2 */ + int direction; /* direction BLADE_TO_PSTN=0 PSTN_TO_BLADE=1 */ + int trunk; + gint32 cas_bchannel; + gchar *cas_frame_label; +} actrace_info_t; + Index: epan/dissectors/Makefile.common =================================================================== --- epan/dissectors/Makefile.common (revision 14788) +++ epan/dissectors/Makefile.common (working copy) @@ -53,6 +53,7 @@ packet-aarp.c \ packet-acap.c \ packet-acse.c \ + packet-actrace.c \ packet-afp.c \ packet-afs.c \ packet-aim.c \ @@ -608,6 +609,7 @@ # corresponding headers DISSECTOR_INCLUDES = \ packet-acse.h \ + packet-actrace.h \ packet-afp.h \ packet-afs-defs.h \ packet-afs-macros.h \ Index: epan/dissectors/packet-q931.c =================================================================== --- epan/dissectors/packet-q931.c (revision 14788) +++ epan/dissectors/packet-q931.c (working copy) @@ -136,50 +136,7 @@ dissect_q931_IEs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *root_tree, proto_tree *q931_tree, gboolean is_tpkt, int offset, int initial_codeset); -/* - * Q.931 message types. - */ -#define Q931_ESCAPE 0x00 -#define Q931_ALERTING 0x01 -#define Q931_CALL_PROCEEDING 0x02 -#define Q931_CONNECT 0x07 -#define Q931_CONNECT_ACK 0x0F -#define Q931_PROGRESS 0x03 -#define Q931_SETUP 0x05 -#define Q931_SETUP_ACK 0x0D -#define Q931_HOLD 0x24 -#define Q931_HOLD_ACK 0x28 -#define Q931_HOLD_REJECT 0x30 -#define Q931_RESUME 0x26 -#define Q931_RESUME_ACK 0x2E -#define Q931_RESUME_REJECT 0x22 -#define Q931_RETRIEVE 0x31 -#define Q931_RETRIEVE_ACK 0x33 -#define Q931_RETRIEVE_REJECT 0x37 -#define Q931_SUSPEND 0x25 -#define Q931_SUSPEND_ACK 0x2D -#define Q931_SUSPEND_REJECT 0x21 -#define Q931_USER_INFORMATION 0x20 -#define Q931_DISCONNECT 0x45 -#define Q931_RELEASE 0x4D -#define Q931_RELEASE_COMPLETE 0x5A -#define Q931_RESTART 0x46 -#define Q931_RESTART_ACK 0x4E -#define Q931_CONGESTION_CONTROL 0x79 -#define Q931_FACILITY 0x62 -#define Q931_INFORMATION 0x7B -#define Q931_NOTIFY 0x6E -#define Q931_REGISTER 0x64 -#define Q931_SEGMENT 0x60 -#define Q931_STATUS 0x7D -#define Q931_STATUS_ENQUIRY 0x75 -#define Q931_VERSION 0x0a -#define Q931_GROUIP_SERVICE 0x06 -#define Q931_GROUIP_SERVICE_ACK 0x0b -#define Q931_RESYNC_REQ 0x08 -#define Q931_RESYNC_RESP 0x09 - -static const value_string q931_message_type_vals[] = { +const value_string q931_message_type_vals[] = { { Q931_ESCAPE, "ESCAPE" }, { Q931_ALERTING, "ALERTING" }, { Q931_CALL_PROCEEDING, "CALL PROCEEDING" }, @@ -2433,6 +2390,9 @@ offset += call_ref_len; } message_type = tvb_get_guint8(tvb, offset); + if(have_valid_q931_pi) { + q931_pi->message_type = message_type; + } if (check_col(pinfo->cinfo, COL_INFO)) { col_add_str(pinfo->cinfo, COL_INFO, val_to_str(message_type, q931_message_type_vals, Index: epan/dissectors/packet-q931.h =================================================================== --- epan/dissectors/packet-q931.h (revision 14788) +++ epan/dissectors/packet-q931.h (working copy) @@ -49,6 +49,7 @@ gchar *called_number; guint8 cause_value; gint32 crv; + guint8 message_type; } q931_packet_info; /* @@ -57,7 +58,51 @@ * libethereal.dll, we need a special declaration. */ ETH_VAR_IMPORT const value_string q931_cause_code_vals[]; +ETH_VAR_IMPORT const value_string q931_message_type_vals[]; extern const value_string q931_protocol_discriminator_vals[]; +/* + * Q.931 message types. + */ +#define Q931_ESCAPE 0x00 +#define Q931_ALERTING 0x01 +#define Q931_CALL_PROCEEDING 0x02 +#define Q931_CONNECT 0x07 +#define Q931_CONNECT_ACK 0x0F +#define Q931_PROGRESS 0x03 +#define Q931_SETUP 0x05 +#define Q931_SETUP_ACK 0x0D +#define Q931_HOLD 0x24 +#define Q931_HOLD_ACK 0x28 +#define Q931_HOLD_REJECT 0x30 +#define Q931_RESUME 0x26 +#define Q931_RESUME_ACK 0x2E +#define Q931_RESUME_REJECT 0x22 +#define Q931_RETRIEVE 0x31 +#define Q931_RETRIEVE_ACK 0x33 +#define Q931_RETRIEVE_REJECT 0x37 +#define Q931_SUSPEND 0x25 +#define Q931_SUSPEND_ACK 0x2D +#define Q931_SUSPEND_REJECT 0x21 +#define Q931_USER_INFORMATION 0x20 +#define Q931_DISCONNECT 0x45 +#define Q931_RELEASE 0x4D +#define Q931_RELEASE_COMPLETE 0x5A +#define Q931_RESTART 0x46 +#define Q931_RESTART_ACK 0x4E +#define Q931_CONGESTION_CONTROL 0x79 +#define Q931_FACILITY 0x62 +#define Q931_INFORMATION 0x7B +#define Q931_NOTIFY 0x6E +#define Q931_REGISTER 0x64 +#define Q931_SEGMENT 0x60 +#define Q931_STATUS 0x7D +#define Q931_STATUS_ENQUIRY 0x75 +#define Q931_VERSION 0x0a +#define Q931_GROUIP_SERVICE 0x06 +#define Q931_GROUIP_SERVICE_ACK 0x0b +#define Q931_RESYNC_REQ 0x08 +#define Q931_RESYNC_RESP 0x09 + #endif
- Follow-Ups:
- SV: [Ethereal-dev] AudioCodes trunk trace protocol (ISDN and CAS)
- From: Anders Broman
- SV: [Ethereal-dev] AudioCodes trunk trace protocol (ISDN and CAS)
- Prev by Date: [Ethereal-dev] Re: [Ethereal-cvs] rev 14773: /trunk/asn1/ftam/: ftam.cnf packet-ftam-template.c packet-ftam-template.h
- Next by Date: Re: [Ethereal-dev] Re: NTAR - PCAP next generation dump file formatimplementation
- Previous by thread: [Ethereal-dev] Re: [Ethereal-cvs] rev 14773: /trunk/asn1/ftam/: ftam.cnf packet-ftam-template.c packet-ftam-template.h
- Next by thread: SV: [Ethereal-dev] AudioCodes trunk trace protocol (ISDN and CAS)
- Index(es):