From 54a520d4a1151c68d0b4e5f09a8d82466fa499f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Valverde?= Date: Wed, 9 Mar 2016 03:17:51 +0000 Subject: Move /asn1 to /epan/dissectors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I1208fe3c2ba428995526f561e8f792b8d871e9a9 Reviewed-on: https://code.wireshark.org/review/14388 Reviewed-by: Pascal Quantin Petri-Dish: Pascal Quantin Reviewed-by: João Valverde --- epan/dissectors/asn1/h225/packet-h225-template.c | 1184 ++++++++++++++++++++++ 1 file changed, 1184 insertions(+) create mode 100644 epan/dissectors/asn1/h225/packet-h225-template.c (limited to 'epan/dissectors/asn1/h225/packet-h225-template.c') diff --git a/epan/dissectors/asn1/h225/packet-h225-template.c b/epan/dissectors/asn1/h225/packet-h225-template.c new file mode 100644 index 0000000000..1fbfe4a07a --- /dev/null +++ b/epan/dissectors/asn1/h225/packet-h225-template.c @@ -0,0 +1,1184 @@ +/* packet-h225.c + * Routines for h225 packet dissection + * Copyright 2005, Anders Broman + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * To quote the author of the previous H323/H225/H245 dissector: + * "This is a complete replacement of the previous limitied dissector + * that Ronnie was crazy enough to write by hand. It was a lot of time + * to hack it by hand, but it is incomplete and buggy and it is good when + * it will go away." + * Ronnie did a great job and all the VoIP users had made good use of it! + * Credit to Tomas Kukosa for developing the asn2wrs compiler. + * + */ + +#include "config.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "packet-tpkt.h" +#include "packet-per.h" +#include "packet-h225.h" +#include "packet-h235.h" +#include "packet-h245.h" +#include "packet-h323.h" +#include "packet-q931.h" +#include "packet-ssl.h" + +#define PNAME "H323-MESSAGES" +#define PSNAME "H.225.0" +#define PFNAME "h225" + +#define UDP_PORT_RAS1 1718 +#define UDP_PORT_RAS2 1719 +#define TCP_PORT_CS 1720 +#define TLS_PORT_CS 1300 + +void proto_register_h225(void); +static void reset_h225_packet_info(h225_packet_info *pi); +static void h225_init_routine(void); +static void ras_call_matching(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, h225_packet_info *pi); + +/* Item of ras request list*/ +typedef struct _h225ras_call_t { + guint32 requestSeqNum; + e_guid_t guid; + guint32 req_num; /* frame number request seen */ + guint32 rsp_num; /* frame number response seen */ + nstime_t req_time; /* arrival time of request */ + gboolean responded; /* true, if request has been responded */ + struct _h225ras_call_t *next_call; /* pointer to next ras request with same SequenceNumber and conversation handle */ +} h225ras_call_t; + + +/* Item of ras-request key list*/ +typedef struct _h225ras_call_info_key { + guint reqSeqNum; + conversation_t *conversation; +} h225ras_call_info_key; + +static h225_packet_info pi_arr[5]; /* We assuming a maximum of 5 H.225 messages per packet */ +static int pi_current=0; +static h225_packet_info *h225_pi=&pi_arr[0]; + +/* Global Memory Chunks for lists and Global hash tables*/ + +static GHashTable *ras_calls[7] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL}; + +/* functions, needed using ras-request and halfcall matching*/ +static h225ras_call_t * find_h225ras_call(h225ras_call_info_key *h225ras_call_key ,int category); +static h225ras_call_t * new_h225ras_call(h225ras_call_info_key *h225ras_call_key, packet_info *pinfo, e_guid_t *guid, int category); +static h225ras_call_t * append_h225ras_call(h225ras_call_t *prev_call, packet_info *pinfo, e_guid_t *guid, int category); + +static dissector_handle_t data_handle; +/* Subdissector tables */ +static dissector_table_t nsp_object_dissector_table; +static dissector_table_t nsp_h221_dissector_table; +static dissector_table_t tp_dissector_table; +static dissector_table_t gef_name_dissector_table; +static dissector_table_t gef_content_dissector_table; + + +static dissector_handle_t h245_handle=NULL; +static dissector_handle_t h245dg_handle=NULL; +static dissector_handle_t h4501_handle=NULL; + +static dissector_handle_t nsp_handle; +static dissector_handle_t tp_handle; + +static next_tvb_list_t h245_list; +static next_tvb_list_t tp_list; + +/* Initialize the protocol and registered fields */ +static int h225_tap = -1; +static int proto_h225 = -1; + +static int hf_h221Manufacturer = -1; +static int hf_h225_ras_req_frame = -1; +static int hf_h225_ras_rsp_frame = -1; +static int hf_h225_ras_dup = -1; +static int hf_h225_ras_deltatime = -1; +static int hf_h225_debug_dissector_try_string = -1; + +#include "packet-h225-hf.c" + +/* Initialize the subtree pointers */ +static gint ett_h225 = -1; +#include "packet-h225-ett.c" + +/* Preferences */ +static guint h225_tls_port = TLS_PORT_CS; +static gboolean h225_reassembly = TRUE; +static gboolean h225_h245_in_tree = TRUE; +static gboolean h225_tp_in_tree = TRUE; + +/* Global variables */ +static guint32 ipv4_address; +static struct e_in6_addr ipv6_address; +static struct e_in6_addr ipv6_address_zeros = {{0}}; +static guint32 ip_port; +static gboolean contains_faststart = FALSE; +static e_guid_t *call_id_guid; + +/* NonStandardParameter */ +static const char *nsiOID; +static guint32 h221NonStandard; +static guint32 t35CountryCode; +static guint32 t35Extension; +static guint32 manufacturerCode; + +/* TunnelledProtocol */ +static const char *tpOID; + +static const value_string ras_message_category[] = { + { 0, "Gatekeeper "}, + { 1, "Registration "}, + { 2, "UnRegistration"}, + { 3, "Admission "}, + { 4, "Bandwidth "}, + { 5, "Disengage "}, + { 6, "Location "}, + { 0, NULL } +}; + +typedef enum _ras_type { + RAS_REQUEST, + RAS_CONFIRM, + RAS_REJECT, + RAS_OTHER +}ras_type; + +typedef enum _ras_category { + RAS_GATEKEEPER, + RAS_REGISTRATION, + RAS_UNREGISTRATION, + RAS_ADMISSION, + RAS_BANDWIDTH, + RAS_DISENGAGE, + RAS_LOCATION, + RAS_OTHERS +}ras_category; + +#define NUM_RAS_STATS 7 + +static gboolean +h225rassrt_packet(void *phs, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *phi) +{ + rtd_data_t* rtd_data = (rtd_data_t*)phs; + rtd_stat_table* rs = &rtd_data->stat_table; + const h225_packet_info *pi=(const h225_packet_info *)phi; + + ras_type rasmsg_type = RAS_OTHER; + ras_category rascategory = RAS_OTHERS; + + if (pi->msg_type != H225_RAS || pi->msg_tag == -1) { + /* No RAS Message or uninitialized msg_tag -> return */ + return FALSE; + } + + if (pi->msg_tag < 21) { + /* */ + rascategory = (ras_category)(pi->msg_tag / 3); + rasmsg_type = (ras_type)(pi->msg_tag % 3); + } + else { + /* No SRT yet (ToDo) */ + return FALSE; + } + + switch(rasmsg_type) { + + case RAS_REQUEST: + if(pi->is_duplicate){ + rs->time_stats[rascategory].req_dup_num++; + } + else { + rs->time_stats[rascategory].open_req_num++; + } + break; + + case RAS_CONFIRM: + /* no break - delay stats are identical for Confirm and Reject */ + case RAS_REJECT: + if(pi->is_duplicate){ + /* Duplicate is ignored */ + rs->time_stats[rascategory].rsp_dup_num++; + } + else if (!pi->request_available) { + /* no request was seen, ignore response */ + rs->time_stats[rascategory].disc_rsp_num++; + } + else { + rs->time_stats[rascategory].open_req_num--; + time_stat_update(&(rs->time_stats[rascategory].rtd[0]),&(pi->delta_time), pinfo); + } + break; + + default: + return FALSE; + } + return TRUE; +} + +#include "packet-h225-fn.c" + +/* Forward declaration we need below */ +void proto_reg_handoff_h225(void); + +/* + * Functions needed for Ras-Hash-Table + */ + +/* compare 2 keys */ +static gint h225ras_call_equal(gconstpointer k1, gconstpointer k2) +{ + const h225ras_call_info_key* key1 = (const h225ras_call_info_key*) k1; + const h225ras_call_info_key* key2 = (const h225ras_call_info_key*) k2; + + return (key1->reqSeqNum == key2->reqSeqNum && + key1->conversation == key2->conversation); +} + +/* calculate a hash key */ +static guint h225ras_call_hash(gconstpointer k) +{ + const h225ras_call_info_key* key = (const h225ras_call_info_key*) k; + + return key->reqSeqNum + GPOINTER_TO_UINT(key->conversation); +} + + +h225ras_call_t * find_h225ras_call(h225ras_call_info_key *h225ras_call_key ,int category) +{ + h225ras_call_t *h225ras_call = NULL; + h225ras_call = (h225ras_call_t *)g_hash_table_lookup(ras_calls[category], h225ras_call_key); + + return h225ras_call; +} + +h225ras_call_t * new_h225ras_call(h225ras_call_info_key *h225ras_call_key, packet_info *pinfo, e_guid_t *guid, int category) +{ + h225ras_call_info_key *new_h225ras_call_key; + h225ras_call_t *h225ras_call = NULL; + + + /* Prepare the value data. + "req_num" and "rsp_num" are frame numbers; + frame numbers are 1-origin, so we use 0 + to mean "we don't yet know in which frame + the reply for this call appears". */ + new_h225ras_call_key = wmem_new(wmem_file_scope(), h225ras_call_info_key); + new_h225ras_call_key->reqSeqNum = h225ras_call_key->reqSeqNum; + new_h225ras_call_key->conversation = h225ras_call_key->conversation; + h225ras_call = wmem_new(wmem_file_scope(), h225ras_call_t); + h225ras_call->req_num = pinfo->num; + h225ras_call->rsp_num = 0; + h225ras_call->requestSeqNum = h225ras_call_key->reqSeqNum; + h225ras_call->responded = FALSE; + h225ras_call->next_call = NULL; + h225ras_call->req_time=pinfo->abs_ts; + h225ras_call->guid=*guid; + /* store it */ + g_hash_table_insert(ras_calls[category], new_h225ras_call_key, h225ras_call); + + return h225ras_call; +} + +h225ras_call_t * append_h225ras_call(h225ras_call_t *prev_call, packet_info *pinfo, e_guid_t *guid, int category _U_) +{ + h225ras_call_t *h225ras_call = NULL; + + /* Prepare the value data. + "req_num" and "rsp_num" are frame numbers; + frame numbers are 1-origin, so we use 0 + to mean "we don't yet know in which frame + the reply for this call appears". */ + h225ras_call = wmem_new(wmem_file_scope(), h225ras_call_t); + h225ras_call->req_num = pinfo->num; + h225ras_call->rsp_num = 0; + h225ras_call->requestSeqNum = prev_call->requestSeqNum; + h225ras_call->responded = FALSE; + h225ras_call->next_call = NULL; + h225ras_call->req_time=pinfo->abs_ts; + h225ras_call->guid=*guid; + + prev_call->next_call = h225ras_call; + return h225ras_call; +} + +/* Init routine for hash tables and delay calculation + This routine will be called by Wireshark, before it + is (re-)dissecting a trace file from beginning. + We need to discard and init any state we've saved */ + +static void +h225_init_routine(void) +{ + int i; + /* create new hash-tables for RAS SRT */ + + for(i=0;i<7;i++) { + ras_calls[i] = g_hash_table_new(h225ras_call_hash, h225ras_call_equal); + } + +} + +static void +h225_cleanup_routine(void) +{ + int i; + + /* free hash-tables for RAS SRT */ + for(i=0;i<7;i++) { + g_hash_table_destroy(ras_calls[i]); + } +} + +static int +dissect_h225_H323UserInformation(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) +{ + proto_item *it; + proto_tree *tr; + int offset = 0; + + pi_current++; + if(pi_current==5){ + pi_current=0; + } + h225_pi=&pi_arr[pi_current]; + + /* Init struct for collecting h225_packet_info */ + reset_h225_packet_info(h225_pi); + h225_pi->msg_type = H225_CS; + + next_tvb_init(&h245_list); + next_tvb_init(&tp_list); + + col_set_str(pinfo->cinfo, COL_PROTOCOL, PSNAME); + col_clear(pinfo->cinfo, COL_INFO); + + it=proto_tree_add_protocol_format(tree, proto_h225, tvb, 0, -1, PSNAME" CS"); + tr=proto_item_add_subtree(it, ett_h225); + + offset = dissect_H323_UserInformation_PDU(tvb, pinfo, tr, NULL); + + if (h245_list.count){ + col_append_str(pinfo->cinfo, COL_PROTOCOL, "/"); + col_set_fence(pinfo->cinfo, COL_PROTOCOL); + } + + next_tvb_call(&h245_list, pinfo, tree, h245dg_handle, data_handle); + next_tvb_call(&tp_list, pinfo, tree, NULL, data_handle); + + tap_queue_packet(h225_tap, pinfo, h225_pi); + + return offset; +} +static int +dissect_h225_h225_RasMessage(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_){ + proto_item *it; + proto_tree *tr; + guint32 offset=0; + + pi_current++; + if(pi_current==5){ + pi_current=0; + } + h225_pi=&pi_arr[pi_current]; + + /* Init struct for collecting h225_packet_info */ + reset_h225_packet_info(h225_pi); + h225_pi->msg_type = H225_RAS; + + col_set_str(pinfo->cinfo, COL_PROTOCOL, PSNAME); + + it=proto_tree_add_protocol_format(tree, proto_h225, tvb, offset, -1, PSNAME" RAS"); + tr=proto_item_add_subtree(it, ett_h225); + + offset = dissect_RasMessage_PDU(tvb, pinfo, tr, NULL); + + ras_call_matching(tvb, pinfo, tr, h225_pi); + + tap_queue_packet(h225_tap, pinfo, h225_pi); + + return offset; +} + + +/* The following values represent the size of their valuestring arrays */ + +#define RAS_MSG_TYPES (sizeof(h225_RasMessage_vals) / sizeof(value_string)) +#define CS_MSG_TYPES (sizeof(T_h323_message_body_vals) / sizeof(value_string)) + +#define GRJ_REASONS (sizeof(GatekeeperRejectReason_vals) / sizeof(value_string)) +#define RRJ_REASONS (sizeof(RegistrationRejectReason_vals) / sizeof(value_string)) +#define URQ_REASONS (sizeof(UnregRequestReason_vals) / sizeof(value_string)) +#define URJ_REASONS (sizeof(UnregRejectReason_vals) / sizeof(value_string)) +#define ARJ_REASONS (sizeof(AdmissionRejectReason_vals) / sizeof(value_string)) +#define BRJ_REASONS (sizeof(BandRejectReason_vals) / sizeof(value_string)) +#define DRQ_REASONS (sizeof(DisengageReason_vals) / sizeof(value_string)) +#define DRJ_REASONS (sizeof(DisengageRejectReason_vals) / sizeof(value_string)) +#define LRJ_REASONS (sizeof(LocationRejectReason_vals) / sizeof(value_string)) +#define IRQNAK_REASONS (sizeof(InfoRequestNakReason_vals) / sizeof(value_string)) +#define REL_CMP_REASONS (sizeof(h225_ReleaseCompleteReason_vals) / sizeof(value_string)) +#define FACILITY_REASONS (sizeof(FacilityReason_vals) / sizeof(value_string)) + +/* TAP STAT INFO */ +typedef enum +{ + MESSAGE_TYPE_COLUMN = 0, + COUNT_COLUMN +} h225_stat_columns; + +typedef struct _h225_table_item { + guint count; /* Message count */ + guint table_idx; /* stat_table index */ +} h225_table_item_t; + +static stat_tap_table_item h225_stat_fields[] = {{TABLE_ITEM_STRING, TAP_ALIGN_LEFT, "Message Type or Reason", "%-25s"}, {TABLE_ITEM_UINT, TAP_ALIGN_RIGHT, "Count", "%d"}}; + +static guint ras_msg_idx[RAS_MSG_TYPES]; +static guint cs_msg_idx[CS_MSG_TYPES]; + +static guint grj_reason_idx[GRJ_REASONS]; +static guint rrj_reason_idx[RRJ_REASONS]; +static guint urq_reason_idx[URQ_REASONS]; +static guint urj_reason_idx[URJ_REASONS]; +static guint arj_reason_idx[ARJ_REASONS]; +static guint brj_reason_idx[BRJ_REASONS]; +static guint drq_reason_idx[DRQ_REASONS]; +static guint drj_reason_idx[DRJ_REASONS]; +static guint lrj_reason_idx[LRJ_REASONS]; +static guint irqnak_reason_idx[IRQNAK_REASONS]; +static guint rel_cmp_reason_idx[REL_CMP_REASONS]; +static guint facility_reason_idx[FACILITY_REASONS]; + +static guint other_idx; + +static void h225_stat_init(stat_tap_table_ui* new_stat, new_stat_tap_gui_init_cb gui_callback, void* gui_data) +{ + int num_fields = sizeof(h225_stat_fields)/sizeof(stat_tap_table_item); + stat_tap_table* table = new_stat_tap_init_table("H.225 Messages and Message Reasons", num_fields, 0, NULL, gui_callback, gui_data); + int row_idx = 0, msg_idx; + stat_tap_table_item_type items[sizeof(h225_stat_fields)/sizeof(stat_tap_table_item)]; + + new_stat_tap_add_table(new_stat, table); + + items[MESSAGE_TYPE_COLUMN].type = TABLE_ITEM_STRING; + items[COUNT_COLUMN].type = TABLE_ITEM_UINT; + items[COUNT_COLUMN].value.uint_value = 0; + + /* Add a row for each value type */ + + msg_idx = 0; + do + { + items[MESSAGE_TYPE_COLUMN].value.string_value = + h225_RasMessage_vals[msg_idx].strptr + ? h225_RasMessage_vals[msg_idx].strptr + : "Unknown RAS message"; + ras_msg_idx[msg_idx] = row_idx; + + new_stat_tap_init_table_row(table, row_idx, num_fields, items); + row_idx++; + msg_idx++; + } while (h225_RasMessage_vals[msg_idx].strptr); + + msg_idx = 0; + do + { + items[MESSAGE_TYPE_COLUMN].value.string_value = + T_h323_message_body_vals[msg_idx].strptr + ? T_h323_message_body_vals[msg_idx].strptr + : "Unknown CS message"; + cs_msg_idx[msg_idx] = row_idx; + + new_stat_tap_init_table_row(table, row_idx, num_fields, items); + row_idx++; + msg_idx++; + } while (T_h323_message_body_vals[msg_idx].strptr); + + msg_idx = 0; + do + { + items[MESSAGE_TYPE_COLUMN].value.string_value = + GatekeeperRejectReason_vals[msg_idx].strptr + ? GatekeeperRejectReason_vals[msg_idx].strptr + : "Unknown gatekeeper reject reason"; + grj_reason_idx[msg_idx] = row_idx; + + new_stat_tap_init_table_row(table, row_idx, num_fields, items); + row_idx++; + msg_idx++; + } while (GatekeeperRejectReason_vals[msg_idx].strptr); + + msg_idx = 0; + do + { + items[MESSAGE_TYPE_COLUMN].value.string_value = + RegistrationRejectReason_vals[msg_idx].strptr + ? RegistrationRejectReason_vals[msg_idx].strptr + : "Unknown registration reject reason"; + rrj_reason_idx[msg_idx] = row_idx; + + new_stat_tap_init_table_row(table, row_idx, num_fields, items); + row_idx++; + msg_idx++; + } while (RegistrationRejectReason_vals[msg_idx].strptr); + + msg_idx = 0; + do + { + items[MESSAGE_TYPE_COLUMN].value.string_value = + UnregRequestReason_vals[msg_idx].strptr + ? UnregRequestReason_vals[msg_idx].strptr + : "Unknown unregistration request reason"; + urq_reason_idx[msg_idx] = row_idx; + + new_stat_tap_init_table_row(table, row_idx, num_fields, items); + row_idx++; + msg_idx++; + } while (UnregRequestReason_vals[msg_idx].strptr); + + msg_idx = 0; + do + { + items[MESSAGE_TYPE_COLUMN].value.string_value = + UnregRejectReason_vals[msg_idx].strptr + ? UnregRejectReason_vals[msg_idx].strptr + : "Unknown unregistration reject reason"; + urj_reason_idx[msg_idx] = row_idx; + + new_stat_tap_init_table_row(table, row_idx, num_fields, items); + row_idx++; + msg_idx++; + } while (UnregRejectReason_vals[msg_idx].strptr); + + msg_idx = 0; + do + { + items[MESSAGE_TYPE_COLUMN].value.string_value = + AdmissionRejectReason_vals[msg_idx].strptr + ? AdmissionRejectReason_vals[msg_idx].strptr + : "Unknown admission reject reason"; + arj_reason_idx[msg_idx] = row_idx; + + new_stat_tap_init_table_row(table, row_idx, num_fields, items); + row_idx++; + msg_idx++; + } while (AdmissionRejectReason_vals[msg_idx].strptr); + + msg_idx = 0; + do + { + items[MESSAGE_TYPE_COLUMN].value.string_value = + BandRejectReason_vals[msg_idx].strptr + ? BandRejectReason_vals[msg_idx].strptr + : "Unknown band reject reason"; + brj_reason_idx[msg_idx] = row_idx; + + new_stat_tap_init_table_row(table, row_idx, num_fields, items); + row_idx++; + msg_idx++; + } while (BandRejectReason_vals[msg_idx].strptr); + + msg_idx = 0; + do + { + items[MESSAGE_TYPE_COLUMN].value.string_value = + DisengageReason_vals[msg_idx].strptr + ? DisengageReason_vals[msg_idx].strptr + : "Unknown disengage reason"; + drq_reason_idx[msg_idx] = row_idx; + + new_stat_tap_init_table_row(table, row_idx, num_fields, items); + row_idx++; + msg_idx++; + } while (DisengageReason_vals[msg_idx].strptr); + + msg_idx = 0; + do + { + items[MESSAGE_TYPE_COLUMN].value.string_value = + DisengageRejectReason_vals[msg_idx].strptr + ? DisengageRejectReason_vals[msg_idx].strptr + : "Unknown disengage reject reason"; + drj_reason_idx[msg_idx] = row_idx; + + new_stat_tap_init_table_row(table, row_idx, num_fields, items); + row_idx++; + msg_idx++; + } while (DisengageRejectReason_vals[msg_idx].strptr); + + msg_idx = 0; + do + { + items[MESSAGE_TYPE_COLUMN].value.string_value = + LocationRejectReason_vals[msg_idx].strptr + ? LocationRejectReason_vals[msg_idx].strptr + : "Unknown location reject reason"; + lrj_reason_idx[msg_idx] = row_idx; + + new_stat_tap_init_table_row(table, row_idx, num_fields, items); + row_idx++; + msg_idx++; + } while (LocationRejectReason_vals[msg_idx].strptr); + + msg_idx = 0; + do + { + items[MESSAGE_TYPE_COLUMN].value.string_value = + InfoRequestNakReason_vals[msg_idx].strptr + ? InfoRequestNakReason_vals[msg_idx].strptr + : "Unknown info request nak reason"; + irqnak_reason_idx[msg_idx] = row_idx; + + new_stat_tap_init_table_row(table, row_idx, num_fields, items); + row_idx++; + msg_idx++; + } while (InfoRequestNakReason_vals[msg_idx].strptr); + + msg_idx = 0; + do + { + items[MESSAGE_TYPE_COLUMN].value.string_value = + h225_ReleaseCompleteReason_vals[msg_idx].strptr + ? h225_ReleaseCompleteReason_vals[msg_idx].strptr + : "Unknown release complete reason"; + rel_cmp_reason_idx[msg_idx] = row_idx; + + new_stat_tap_init_table_row(table, row_idx, num_fields, items); + row_idx++; + msg_idx++; + } while (h225_ReleaseCompleteReason_vals[msg_idx].strptr); + + msg_idx = 0; + do + { + items[MESSAGE_TYPE_COLUMN].value.string_value = + FacilityReason_vals[msg_idx].strptr + ? FacilityReason_vals[msg_idx].strptr + : "Unknown facility reason"; + facility_reason_idx[msg_idx] = row_idx; + + new_stat_tap_init_table_row(table, row_idx, num_fields, items); + row_idx++; + msg_idx++; + } while (FacilityReason_vals[msg_idx].strptr); + + + items[MESSAGE_TYPE_COLUMN].value.string_value = "Unknown H.225 message"; + new_stat_tap_init_table_row(table, row_idx, num_fields, items); + other_idx = row_idx; +} + +static gboolean +h225_stat_packet(void *tapdata, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *hpi_ptr) +{ + new_stat_data_t* stat_data = (new_stat_data_t*)tapdata; + const h225_packet_info *hpi = (const h225_packet_info *)hpi_ptr; + int tag_idx = -1; + int reason_idx = -1; + + if(hpi->msg_tag < 0) { /* uninitialized */ + return FALSE; + } + + switch (hpi->msg_type) { + + case H225_RAS: + tag_idx = ras_msg_idx[MIN(hpi->msg_tag, (int)RAS_MSG_TYPES-1)]; + + /* Look for reason tag */ + if(hpi->reason < 0) { /* uninitialized */ + break; + } + + switch(hpi->msg_tag) { + + case 2: /* GRJ */ + reason_idx = grj_reason_idx[MIN(hpi->reason, (int)GRJ_REASONS-1)]; + break; + case 5: /* RRJ */ + reason_idx = rrj_reason_idx[MIN(hpi->reason, (int)RRJ_REASONS-1)]; + break; + case 6: /* URQ */ + reason_idx = urq_reason_idx[MIN(hpi->reason, (int)URQ_REASONS-1)]; + break; + case 8: /* URJ */ + reason_idx = urj_reason_idx[MIN(hpi->reason, (int)URJ_REASONS-1)]; + break; + case 11: /* ARJ */ + reason_idx = arj_reason_idx[MIN(hpi->reason, (int)ARJ_REASONS-1)]; + break; + case 14: /* BRJ */ + reason_idx = brj_reason_idx[MIN(hpi->reason, (int)BRJ_REASONS-1)]; + break; + case 15: /* DRQ */ + reason_idx = drq_reason_idx[MIN(hpi->reason, (int)DRQ_REASONS-1)]; + break; + case 17: /* DRJ */ + reason_idx = drj_reason_idx[MIN(hpi->reason, (int)DRJ_REASONS-1)]; + break; + case 20: /* LRJ */ + reason_idx = lrj_reason_idx[MIN(hpi->reason, (int)LRJ_REASONS-1)]; + break; + case 29: /* IRQ Nak */ + reason_idx = irqnak_reason_idx[MIN(hpi->reason, (int)IRQNAK_REASONS-1)]; + break; + default: + /* do nothing */ + break; + } + + break; + + case H225_CS: + tag_idx = cs_msg_idx[MIN(hpi->msg_tag, (int)CS_MSG_TYPES-1)]; + + /* Look for reason tag */ + if(hpi->reason < 0) { /* uninitialized */ + break; + } + + switch(hpi->msg_tag) { + + case 5: /* ReleaseComplete */ + reason_idx = rel_cmp_reason_idx[MIN(hpi->reason, (int)REL_CMP_REASONS-1)]; + break; + case 6: /* Facility */ + reason_idx = facility_reason_idx[MIN(hpi->reason, (int)FACILITY_REASONS-1)]; + break; + default: + /* do nothing */ + break; + } + + break; + + case H225_OTHERS: + default: + tag_idx = other_idx; + } + + if (tag_idx >= 0) { + stat_tap_table*table = g_array_index(stat_data->stat_tap_data->tables, stat_tap_table*, 0); + stat_tap_table_item_type* msg_data = new_stat_tap_get_field_data(table, tag_idx, COUNT_COLUMN);; + msg_data->value.uint_value++; + new_stat_tap_set_field_data(table, tag_idx, COUNT_COLUMN, msg_data); + + if (reason_idx >= 0) { + msg_data = new_stat_tap_get_field_data(table, reason_idx, COUNT_COLUMN);; + msg_data->value.uint_value++; + new_stat_tap_set_field_data(table, reason_idx, COUNT_COLUMN, msg_data); + } + + return TRUE; + } + return FALSE; +} + +static void +h225_stat_reset(stat_tap_table* table) +{ + guint element; + stat_tap_table_item_type* item_data; + + for (element = 0; element < table->num_elements; element++) + { + item_data = new_stat_tap_get_field_data(table, element, COUNT_COLUMN); + item_data->value.uint_value = 0; + new_stat_tap_set_field_data(table, element, COUNT_COLUMN, item_data); + } +} + +/*--- proto_register_h225 -------------------------------------------*/ +void proto_register_h225(void) { + + /* List of fields */ + static hf_register_info hf[] = { + { &hf_h221Manufacturer, + { "H.225 Manufacturer", "h225.Manufacturer", FT_UINT32, BASE_HEX, + VALS(H221ManufacturerCode_vals), 0, "h225.H.221 Manufacturer", HFILL }}, + + { &hf_h225_ras_req_frame, + { "RAS Request Frame", "h225.ras.reqframe", FT_FRAMENUM, BASE_NONE, + NULL, 0, NULL, HFILL }}, + + { &hf_h225_ras_rsp_frame, + { "RAS Response Frame", "h225.ras.rspframe", FT_FRAMENUM, BASE_NONE, + NULL, 0, NULL, HFILL }}, + + { &hf_h225_ras_dup, + { "Duplicate RAS Message", "h225.ras.dup", FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_h225_ras_deltatime, + { "RAS Service Response Time", "h225.ras.timedelta", FT_RELATIVE_TIME, BASE_NONE, + NULL, 0, "Timedelta between RAS-Request and RAS-Response", HFILL }}, + + { &hf_h225_debug_dissector_try_string, + { "*** DEBUG dissector_try_string", "h225.debug.dissector_try_string", FT_STRING, BASE_NONE, + NULL, 0, NULL, HFILL }}, + +#include "packet-h225-hfarr.c" + }; + + /* List of subtrees */ + static gint *ett[] = { + &ett_h225, +#include "packet-h225-ettarr.c" + }; + + static tap_param h225_stat_params[] = { + { PARAM_FILTER, "filter", "Filter", NULL, TRUE } + }; + + static stat_tap_table_ui h225_stat_table = { + REGISTER_STAT_GROUP_TELEPHONY, + "H.225", + PFNAME, + "h225,counter", + h225_stat_init, + h225_stat_packet, + h225_stat_reset, + NULL, + NULL, + sizeof(h225_stat_fields)/sizeof(stat_tap_table_item), h225_stat_fields, + sizeof(h225_stat_params)/sizeof(tap_param), h225_stat_params, + NULL + }; + + module_t *h225_module; + int proto_h225_ras; + + /* Register protocol */ + proto_h225 = proto_register_protocol(PNAME, PSNAME, PFNAME); + + /* Create a "fake" protocol to get proper display strings for SRT dialogs */ + proto_h225_ras = proto_register_protocol("H.225 RAS", "H.225 RAS", "h225_ras"); + + /* Register fields and subtrees */ + proto_register_field_array(proto_h225, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + h225_module = prefs_register_protocol(proto_h225, proto_reg_handoff_h225); + prefs_register_uint_preference(h225_module, "tls.port", + "H.225 TLS Port", + "H.225 Server TLS Port", + 10, &h225_tls_port); + prefs_register_bool_preference(h225_module, "reassembly", + "Reassemble H.225 messages spanning multiple TCP segments", + "Whether the H.225 dissector should reassemble messages spanning multiple TCP segments." + " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.", + &h225_reassembly); + prefs_register_bool_preference(h225_module, "h245_in_tree", + "Display tunnelled H.245 inside H.225.0 tree", + "ON - display tunnelled H.245 inside H.225.0 tree, OFF - display tunnelled H.245 in root tree after H.225.0", + &h225_h245_in_tree); + prefs_register_bool_preference(h225_module, "tp_in_tree", + "Display tunnelled protocols inside H.225.0 tree", + "ON - display tunnelled protocols inside H.225.0 tree, OFF - display tunnelled protocols in root tree after H.225.0", + &h225_tp_in_tree); + + register_dissector(PFNAME, dissect_h225_H323UserInformation, proto_h225); + register_dissector("h323ui",dissect_h225_H323UserInformation, proto_h225); + register_dissector("h225.ras", dissect_h225_h225_RasMessage, proto_h225); + + nsp_object_dissector_table = register_dissector_table("h225.nsp.object", "H.225 NonStandardParameter (object)", FT_STRING, BASE_NONE, DISSECTOR_TABLE_ALLOW_DUPLICATE); + nsp_h221_dissector_table = register_dissector_table("h225.nsp.h221", "H.225 NonStandardParameter (h221)", FT_UINT32, BASE_HEX, DISSECTOR_TABLE_ALLOW_DUPLICATE); + tp_dissector_table = register_dissector_table("h225.tp", "H.225 TunnelledProtocol", FT_STRING, BASE_NONE, DISSECTOR_TABLE_ALLOW_DUPLICATE); + gef_name_dissector_table = register_dissector_table("h225.gef.name", "H.225 Generic Extensible Framework (names)", FT_STRING, BASE_NONE, DISSECTOR_TABLE_ALLOW_DUPLICATE); + gef_content_dissector_table = register_dissector_table("h225.gef.content", "H.225 Generic Extensible Framework", FT_STRING, BASE_NONE, DISSECTOR_TABLE_ALLOW_DUPLICATE); + + register_init_routine(&h225_init_routine); + register_cleanup_routine(&h225_cleanup_routine); + h225_tap = register_tap(PFNAME); + + register_rtd_table(proto_h225_ras, PFNAME, NUM_RAS_STATS, 1, ras_message_category, h225rassrt_packet, NULL); + + register_stat_tap_table_ui(&h225_stat_table); + + oid_add_from_string("Version 1","0.0.8.2250.0.1"); + oid_add_from_string("Version 2","0.0.8.2250.0.2"); + oid_add_from_string("Version 3","0.0.8.2250.0.3"); + oid_add_from_string("Version 4","0.0.8.2250.0.4"); + oid_add_from_string("Version 5","0.0.8.2250.0.5"); + oid_add_from_string("Version 6","0.0.8.2250.0.6"); +} + + +/*--- proto_reg_handoff_h225 ---------------------------------------*/ +void +proto_reg_handoff_h225(void) +{ + static gboolean h225_prefs_initialized = FALSE; + static dissector_handle_t h225ras_handle, q931_tpkt_handle; + static guint saved_h225_tls_port; + + if (!h225_prefs_initialized) { + h225ras_handle=find_dissector("h225.ras"); + dissector_add_uint("udp.port", UDP_PORT_RAS1, h225ras_handle); + dissector_add_uint("udp.port", UDP_PORT_RAS2, h225ras_handle); + + h245_handle = find_dissector("h245"); + h245dg_handle = find_dissector("h245dg"); + h4501_handle = find_dissector("h4501"); + data_handle = find_dissector("data"); + h225_prefs_initialized = TRUE; + q931_tpkt_handle = find_dissector("q931.tpkt"); + } else { + ssl_dissector_delete(saved_h225_tls_port, q931_tpkt_handle); + } + + saved_h225_tls_port = h225_tls_port; + ssl_dissector_add(saved_h225_tls_port, q931_tpkt_handle); +} + + +static void reset_h225_packet_info(h225_packet_info *pi) +{ + if(pi == NULL) { + return; + } + + pi->msg_type = H225_OTHERS; + pi->cs_type = H225_OTHER; + pi->msg_tag = -1; + pi->reason = -1; + pi->requestSeqNum = 0; + memset(&pi->guid,0,sizeof pi->guid); + pi->is_duplicate = FALSE; + pi->request_available = FALSE; + pi->is_faststart = FALSE; + pi->is_h245 = FALSE; + pi->is_h245Tunneling = FALSE; + pi->h245_address = 0; + pi->h245_port = 0; + pi->frame_label[0] = '\0'; + pi->dialedDigits[0] = '\0'; + pi->is_destinationInfo = FALSE; +} + +/* + The following function contains the routines for RAS request/response matching. + A RAS response matches with a request, if both messages have the same + RequestSequenceNumber, belong to the same IP conversation and belong to the same + RAS "category" (e.g. Admission, Registration). + + We use hashtables to access the lists of RAS calls (request/response pairs). + We have one hashtable for each RAS category. The hashkeys consist of the + non-unique 16-bit RequestSequenceNumber and values representing the conversation. + + In big capture files, we might get different requests with identical keys. + These requests aren't necessarily duplicates. They might be valid new requests. + At the moment we just use the timedelta between the last valid and the new request + to decide if the new request is a duplicate or not. There might be better ways. + Two thresholds are defined below. + + However the decision is made, another problem arises. We can't just add those + requests to our hashtables. Instead we create lists of RAS calls with identical keys. + The hashtables for RAS calls contain now pointers to the first RAS call in a list of + RAS calls with identical keys. + These lists aren't expected to contain more than 3 items and are usually single item + lists. So we don't need an expensive but intelligent way to access these lists + (e.g. hashtables). Just walk through such a list. +*/ + +#define THRESHOLD_REPEATED_RESPONDED_CALL 300 +#define THRESHOLD_REPEATED_NOT_RESPONDED_CALL 1800 + +static void ras_call_matching(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, h225_packet_info *pi) +{ + proto_item *hidden_item; + conversation_t* conversation = NULL; + h225ras_call_info_key h225ras_call_key; + h225ras_call_t *h225ras_call = NULL; + nstime_t delta; + guint msg_category; + + if(pi->msg_type == H225_RAS && pi->msg_tag < 21) { + /* make RAS request/response matching only for tags from 0 to 20 for now */ + + msg_category = pi->msg_tag / 3; + if(pi->msg_tag % 3 == 0) { /* Request Message */ + conversation = find_or_create_conversation(pinfo); + + /* prepare the key data */ + h225ras_call_key.reqSeqNum = pi->requestSeqNum; + h225ras_call_key.conversation = conversation; + + /* look up the request */ + h225ras_call = find_h225ras_call(&h225ras_call_key ,msg_category); + + if (h225ras_call != NULL) { + /* We've seen requests with this reqSeqNum, with the same + source and destination, before - do we have + *this* request already? */ + /* Walk through list of ras requests with identical keys */ + do { + if (pinfo->num == h225ras_call->req_num) { + /* We have seen this request before -> do nothing */ + break; + } + + /* if end of list is reached, exit loop and decide if request is duplicate or not. */ + if (h225ras_call->next_call == NULL) { + if ( (pinfo->num > h225ras_call->rsp_num && h225ras_call->rsp_num != 0 + && pinfo->abs_ts.secs > (h225ras_call->req_time.secs + THRESHOLD_REPEATED_RESPONDED_CALL) ) + ||(pinfo->num > h225ras_call->req_num && h225ras_call->rsp_num == 0 + && pinfo->abs_ts.secs > (h225ras_call->req_time.secs + THRESHOLD_REPEATED_NOT_RESPONDED_CALL) ) ) + { + /* if last request has been responded + and this request appears after last response (has bigger frame number) + and last request occurred more than 300 seconds ago, + or if last request hasn't been responded + and this request appears after last request (has bigger frame number) + and last request occurred more than 1800 seconds ago, + we decide that we have a new request */ + /* Append new ras call to list */ + h225ras_call = append_h225ras_call(h225ras_call, pinfo, &pi->guid, msg_category); + } else { + /* No, so it's a duplicate request. + Mark it as such. */ + pi->is_duplicate = TRUE; + hidden_item = proto_tree_add_uint(tree, hf_h225_ras_dup, tvb, 0,0, pi->requestSeqNum); + PROTO_ITEM_SET_HIDDEN(hidden_item); + } + break; + } + h225ras_call = h225ras_call->next_call; + } while (h225ras_call != NULL ); + } + else { + h225ras_call = new_h225ras_call(&h225ras_call_key, pinfo, &pi->guid, msg_category); + } + + /* add link to response frame, if available */ + if(h225ras_call && h225ras_call->rsp_num != 0){ + proto_item *ti = + proto_tree_add_uint_format(tree, hf_h225_ras_rsp_frame, tvb, 0, 0, h225ras_call->rsp_num, + "The response to this request is in frame %u", + h225ras_call->rsp_num); + PROTO_ITEM_SET_GENERATED(ti); + } + + /* end of request message handling*/ + } + else { /* Confirm or Reject Message */ + conversation = find_conversation(pinfo->num, &pinfo->src, + &pinfo->dst, pinfo->ptype, pinfo->srcport, + pinfo->destport, 0); + if (conversation != NULL) { + /* look only for matching request, if + matching conversation is available. */ + h225ras_call_key.reqSeqNum = pi->requestSeqNum; + h225ras_call_key.conversation = conversation; + h225ras_call = find_h225ras_call(&h225ras_call_key ,msg_category); + if(h225ras_call) { + /* find matching ras_call in list of ras calls with identical keys */ + do { + if (pinfo->num == h225ras_call->rsp_num) { + /* We have seen this response before -> stop now with matching ras call */ + break; + } + + /* Break when list end is reached */ + if(h225ras_call->next_call == NULL) { + break; + } + h225ras_call = h225ras_call->next_call; + } while (h225ras_call != NULL) ; + + if (!h225ras_call) { + return; + } + + /* if this is an ACF, ARJ or DCF, DRJ, give guid to tap and make it filterable */ + if (msg_category == 3 || msg_category == 5) { + pi->guid = h225ras_call->guid; + hidden_item = proto_tree_add_guid(tree, hf_h225_guid, tvb, 0, GUID_LEN, &pi->guid); + PROTO_ITEM_SET_HIDDEN(hidden_item); + } + + if (h225ras_call->rsp_num == 0) { + /* We have not yet seen a response to that call, so + this must be the first response; remember its + frame number. */ + h225ras_call->rsp_num = pinfo->num; + } + else { + /* We have seen a response to this call - but was it + *this* response? */ + if (h225ras_call->rsp_num != pinfo->num) { + /* No, so it's a duplicate response. + Mark it as such. */ + pi->is_duplicate = TRUE; + hidden_item = proto_tree_add_uint(tree, hf_h225_ras_dup, tvb, 0,0, pi->requestSeqNum); + PROTO_ITEM_SET_HIDDEN(hidden_item); + } + } + + if(h225ras_call->req_num != 0){ + proto_item *ti; + h225ras_call->responded = TRUE; + pi->request_available = TRUE; + + /* Indicate the frame to which this is a reply. */ + ti = proto_tree_add_uint_format(tree, hf_h225_ras_req_frame, tvb, 0, 0, h225ras_call->req_num, + "This is a response to a request in frame %u", h225ras_call->req_num); + PROTO_ITEM_SET_GENERATED(ti); + + /* Calculate RAS Service Response Time */ + nstime_delta(&delta, &pinfo->abs_ts, &h225ras_call->req_time); + pi->delta_time = delta; /* give it to tap */ + + /* display Ras Service Response Time and make it filterable */ + ti = proto_tree_add_time(tree, hf_h225_ras_deltatime, tvb, 0, 0, &(pi->delta_time)); + PROTO_ITEM_SET_GENERATED(ti); + } + } + } + } + } +} + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local Variables: + * c-basic-offset: 2 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=2 tabstop=8 expandtab: + * :indentSize=2:tabSize=8:noTabs=true: + */ -- cgit v1.2.3