/* packet-actrace.c * Routines for AudioCodes Trunk traces packet disassembly * * Copyright (c) 2005 by Alejandro Vaquero * * $Id: packet-actrace.c 27389 2009-02-06 20:33:53Z wmeier $ * * Wireshark - Network traffic analyzer * By Gerald Combs * 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 #include #include #include #include #include #include "packet-actrace.h" #include #define UDP_PORT_ACTRACE 2428 #define NOT_ACTRACE 0 #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"}, {0, NULL} }; 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, "#"}, {0, NULL} }; 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"}, {0, NULL} }; #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"}, {0, NULL} }; 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"}, {0, NULL} }; 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"}, {0, NULL} }; #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"}, {0, NULL} }; 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"}, {0, NULL} }; /* 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"}, {0, NULL} }; /* * Define the tree for actrace */ static int ett_actrace = -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 guint global_actrace_udp_port = UDP_PORT_ACTRACE; /* Some basic utility functions that are specific to this dissector */ static int is_actrace(tvbuff_t *tvb, gint offset); /* * The dissect functions */ static void dissect_actrace_cas(tvbuff_t *tvb, packet_info *pinfo, proto_tree *actrace_tree); static void dissect_actrace_isdn(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_tree *actrace_tree); /************************************************************************ * dissect_actrace - The dissector for the AudioCodes Trace prtocol ************************************************************************/ static int dissect_actrace(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *actrace_tree; proto_item *ti; int actrace_protocol; /* Initialize variables */ actrace_tree = NULL; /* * 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. */ actrace_protocol = is_actrace(tvb, 0); if (actrace_protocol != NOT_ACTRACE) { /* * 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_set_str(pinfo->cinfo, COL_PROTOCOL, "AC_TRACE"); if (check_col(pinfo->cinfo, COL_INFO)) col_clear(pinfo->cinfo, COL_INFO); 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 (actrace_protocol) { case ACTRACE_CAS: dissect_actrace_cas(tvb, pinfo, actrace_tree); break; case ACTRACE_ISDN: dissect_actrace_isdn(tvb, pinfo, tree, actrace_tree); break; } return tvb_length(tvb); } return 0; } /* Dissect an individual actrace CAS message */ static void dissect_actrace_cas(tvbuff_t *tvb, packet_info *pinfo, proto_tree *actrace_tree) { /* Declare variables */ gint sectionlen; gint tvb_sectionend,tvb_sectionbegin; 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; value = 0; if (check_col(pinfo->cinfo, COL_PROTOCOL)) col_set_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 = ep_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 = ep_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 = ep_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 = ep_strdup_printf("MF: %u", par1); } else if (par0 == SEND_TYPE_ADDRESS ) { frame_label = ep_strdup("MF: DNIS digit"); } else if (par0 == SEND_TYPE_ANI ) { frame_label = ep_strdup("MF: ANI digit"); } else if (par0 == SEND_TYPE_SOURCE_CATEGORY ) { frame_label = ep_strdup("MF: src_category"); } else if (par0 == SEND_TYPE_TRANSFER_CAPABILITY ) { frame_label = ep_strdup("MF: trf_capability"); } else if (par0 == SEND_TYPE_INTER_EXCHANGE_SWITCH ) { frame_label = ep_strdup("MF: inter_exch_sw"); } } else if (function == SEND_CAS) { frame_label = ep_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 = ep_strdup("DTMF/MF: sending DNIS"); } else if (par0 == SEND_TYPE_ANI ) { frame_label = ep_strdup("DTMF/MF: sending ANI"); } } } if (frame_label != NULL) { /* Initialise packet info for passing to tap */ actrace_pi = ep_alloc(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) { /* 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 = ep_alloc(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_set_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." "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 gboolean actrace_prefs_initialized = FALSE; static dissector_handle_t actrace_handle; static guint actrace_udp_port; if (!actrace_prefs_initialized) { actrace_handle = new_create_dissector_handle(dissect_actrace, proto_actrace); /* Get a handle for the lapd dissector. */ lapd_handle = find_dissector("lapd"); 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: NOT_ACTRACE if there isn't an AutioCode trace packet at offset * in tvb, ACTRACE_CAS if there's a CAS packet there, ACTRACE_ISDN if * there's an ISDN packet there. */ static int is_actrace(tvbuff_t *tvb, gint offset) { gint tvb_len; gint32 source, isdn_header; tvb_len = tvb_reported_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)) ) return ACTRACE_CAS; /* 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)) ) return ACTRACE_ISDN; return NOT_ACTRACE; }