wireshark/epan/dissectors/packet-megaco.c
John Thacker 9319394af1 MEGACO: Reset bracket counters after a Topology Descriptor
After parsing a Topology Descriptor at the start of a request
or reply command, reset the left and right bracket counters
before going back to the top of the loop to parse the next
command, just like how done at the end of the while loop with
a normal command.

Prevents marking as malformed packets which have a Topology Descriptor
followed by a single command (e.g. Move) without any trailing
descriptors, and hence no more left brackets.
2022-06-17 12:52:13 +00:00

3957 lines
168 KiB
C

/* packet-megaco.c
* Routines for megaco packet disassembly
* RFC 3015
*
* Christian Falckenberg, 2002/10/17
* Copyright (c) 2002 by Christian Falckenberg
* <christian.falckenberg@nortelnetworks.com>
*
* Christoph Wiest, 2003/06/28
* Modified 2003 by Christoph Wiest
* <ch.wiest@tesionmail.de>
* Modified 2004 by Anders Broman
* <anders.broman@ericsson.com>
* To handle TPKT headers if over TCP
* Modified 2005 by Karl Knoebl
* <karl.knoebl@siemens.com>
* provide info to COL_INFO and some "prettification"
*
* Copyright (c) 2006 Anders Broman <anders.broman@ericsson.com>
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1999 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "config.h"
#include <stdlib.h>
#include <epan/packet.h>
#include <epan/exceptions.h>
#include <epan/tap.h>
#include <epan/rtd_table.h>
#include <epan/prefs.h>
#include <epan/prefs-int.h>
#include <epan/exported_pdu.h>
#include <epan/asn1.h>
#include <epan/sctpppids.h>
#include <wsutil/strtoi.h>
#include "packet-ber.h"
#include "packet-tpkt.h"
#include "packet-h245.h"
#include "packet-h248.h"
#include "packet-ip.h"
#include "packet-http.h"
#include "packet-sdp.h"
void proto_register_megaco(void);
void proto_reg_handoff_megaco(void);
#define PORT_MEGACO_TXT 2944
#define PORT_MEGACO_BIN 2945
static pref_t *sip_hide_generated_call_ids;
/* Define the megaco proto */
static int proto_megaco = -1;
/* Define headers for megaco */
static int hf_megaco_start = -1;
static int hf_megaco_version = -1;
static int hf_megaco_transaction = -1;
static int hf_megaco_transid = -1;
static int hf_megaco_Context = -1;
/* static int hf_megaco_command_line = -1; */
static int hf_megaco_command = -1;
static int hf_megaco_command_optional = -1;
static int hf_megaco_wildcard_response = -1;
static int hf_megaco_termid = -1;
/* Define headers in subtree for megaco */
static int hf_megaco_modem_descriptor = -1;
static int hf_megaco_multiplex_descriptor = -1;
static int hf_megaco_media_descriptor = -1;
static int hf_megaco_Local_descriptor = -1;
static int hf_megaco_events_descriptor = -1;
static int hf_megaco_signal_descriptor = -1;
static int hf_megaco_audit_descriptor = -1;
/* static int hf_megaco_servicechange_descriptor = -1; */
static int hf_megaco_digitmap_descriptor = -1;
static int hf_megaco_statistics_descriptor = -1;
static int hf_megaco_observedevents_descriptor = -1;
static int hf_megaco_topology_descriptor = -1;
static int hf_megaco_error_descriptor = -1;
static int hf_megaco_error_code = -1;
static int hf_megaco_error_string = -1;
static int hf_megaco_TerminationState_descriptor= -1;
static int hf_megaco_Remote_descriptor = -1;
static int hf_megaco_LocalControl_descriptor = -1;
static int hf_megaco_packages_descriptor = -1;
static int hf_megaco_Service_State = -1;
static int hf_megaco_Event_Buffer_Control = -1;
static int hf_megaco_mode = -1;
static int hf_megaco_reserve_group = -1;
static int hf_megaco_h324_muxtbl_in = -1;
static int hf_megaco_h324_muxtbl_out = -1;
static int hf_megaco_ds_dscp = -1;
static int hf_megaco_gm_saf = -1;
static int hf_megaco_gm_sam = -1;
static int hf_megaco_gm_spf = -1;
static int hf_megaco_gm_spr = -1;
static int hf_megaco_gm_esas = -1;
static int hf_megaco_tman_pol = -1;
static int hf_megaco_gm_rsb = -1;
static int hf_megaco_tman_sdr = -1;
static int hf_megaco_tman_mbs = -1;
static int hf_megaco_tman_pdr = -1;
static int hf_megaco_tman_dvt = -1;
static int hf_megaco_ipdc_realm = -1;
static int hf_megaco_h324_h223capr = -1;
static int hf_megaco_reserve_value = -1;
static int hf_megaco_streamid = -1;
static int hf_megaco_requestid = -1;
static int hf_megaco_pkgdname = -1;
static int hf_megaco_mId = -1;
static int hf_megaco_h245 = -1;
static int hf_megaco_h223Capability = -1;
static int hf_megaco_audititem = -1;
static int hf_megaco_priority = -1;
/* Define the trees for megaco */
static int ett_megaco = -1;
static int ett_megaco_message = -1;
static int ett_megaco_message_body = -1;
static int ett_megaco_context = -1;
static int ett_megaco_command_line = -1;
static int ett_megaco_mediadescriptor = -1;
static int ett_megaco_descriptors = -1;
static int ett_megaco_raw_text = -1;
static int ett_megaco_error_descriptor = -1;
static int ett_megaco_TerminationState = -1;
static int ett_megaco_Localdescriptor = -1;
static int ett_megaco_Remotedescriptor = -1;
static int ett_megaco_LocalControldescriptor = -1;
static int ett_megaco_auditdescriptor = -1;
static int ett_megaco_eventsdescriptor = -1;
static int ett_megaco_statisticsdescriptor = -1;
static int ett_megaco_observedeventsdescriptor = -1;
static int ett_megaco_observedevent = -1;
static int ett_megaco_packagesdescriptor = -1;
static int ett_megaco_requestedevent = -1;
static int ett_megaco_signalsdescriptor = -1;
static int ett_megaco_requestedsignal = -1;
static int ett_megaco_h245 = -1;
static gcp_hf_ett_t megaco_ctx_ids = {{-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1}};
static expert_field ei_megaco_errored_command = EI_INIT;
static expert_field ei_megaco_no_command = EI_INIT;
static expert_field ei_megaco_no_descriptor = EI_INIT;
static expert_field ei_megaco_error_descriptor_transaction_list = EI_INIT;
static expert_field ei_megaco_parse_error = EI_INIT;
static expert_field ei_megaco_audit_descriptor = EI_INIT;
static expert_field ei_megaco_signal_descriptor = EI_INIT;
static expert_field ei_megaco_reason_invalid = EI_INIT;
static expert_field ei_megaco_error_code_invalid = EI_INIT;
static expert_field ei_megaco_invalid_sdr = EI_INIT;
static dissector_handle_t megaco_text_handle;
static int megaco_tap = -1;
static gint exported_pdu_tap = -1;
/* patterns used for tvb_ws_mempbrk_pattern_guint8 */
static ws_mempbrk_pattern pbrk_whitespace;
static ws_mempbrk_pattern pbrk_braces;
/* Used when command type is needed to diferentiate parsing, extend as needed */
typedef enum
{
MEGACO_CMD_NOT_SET = 0,
MEGACO_CMD_PRIORITY,
} megaco_commands_enum_t;
/*
* Here are the global variables associated with
* the various user definable characteristics of the dissection
*
* MEGACO has two kinds of message formats: text and binary
*
* global_megaco_raw_text determines whether we are going to display
* the raw text of the megaco message, much like the HTTP dissector does.
*
* global_megaco_dissect_tree determines whether we are going to display
* a detailed tree that expresses a somewhat more semantically meaningful
* decode.
*/
static guint global_megaco_txt_sctp_port = PORT_MEGACO_TXT;
#if 0
static guint global_megaco_bin_sctp_port = PORT_MEGACO_BIN;
static guint global_megaco_bin_tcp_port = PORT_MEGACO_BIN;
static guint global_megaco_bin_udp_port = PORT_MEGACO_BIN;
#endif
static gboolean global_megaco_raw_text = TRUE;
static gboolean global_megaco_dissect_tree = TRUE;
static const value_string megaco_context_vals[] = {
{ CHOOSE_CONTEXT, "Choose one" },
{ ALL_CONTEXTS, "All" },
{ NULL_CONTEXT, "NULL" },
{ 0, NULL }
};
/* Some basic utility functions that are specific to this dissector */
static gint megaco_tvb_skip_wsp(tvbuff_t *tvb, gint offset);
static gint megaco_tvb_skip_wsp_return(tvbuff_t *tvb, gint offset);
#define NUM_TIMESTATS 12
static const value_string megaco_message_type[] = {
{ 0, "ADD "},
{ 1, "MOVE"},
{ 2, "MDFY"},
{ 3, "SUBT"},
{ 4, "AUCP"},
{ 5, "AUVL"},
{ 6, "NTFY"},
{ 7, "SVCC"},
{ 8, "TOPO"},
{ 9, "NONE"},
{ 10, "ALL "},
{ 0, NULL}
};
#define GCP_CMD_REPLY_CASE \
case GCP_CMD_ADD_REPLY: \
case GCP_CMD_MOVE_REPLY: \
case GCP_CMD_MOD_REPLY: \
case GCP_CMD_SUB_REPLY: \
case GCP_CMD_AUDITCAP_REPLY: \
case GCP_CMD_AUDITVAL_REPLY: \
case GCP_CMD_NOTIFY_REPLY: \
case GCP_CMD_SVCCHG_REPLY: \
case GCP_CMD_TOPOLOGY_REPLY: \
case GCP_CMD_REPLY:
#define GCP_CMD_REQ_CASE \
case GCP_CMD_ADD_REQ: \
case GCP_CMD_MOVE_REQ: \
case GCP_CMD_MOD_REQ: \
case GCP_CMD_SUB_REQ: \
case GCP_CMD_AUDITCAP_REQ: \
case GCP_CMD_AUDITVAL_REQ: \
case GCP_CMD_NOTIFY_REQ: \
case GCP_CMD_SVCCHG_REQ: \
case GCP_CMD_TOPOLOGY_REQ: \
case GCP_CMD_CTX_ATTR_AUDIT_REQ: \
case GCP_CMD_OTHER_REQ:
static gboolean
megacostat_is_duplicate_reply(const gcp_cmd_t* cmd)
{
switch (cmd->type) {
GCP_CMD_REPLY_CASE
{
gcp_cmd_msg_t *cmd_msg;
/* cycle through commands to find same command in the transaction */
for (cmd_msg = cmd->trx->cmds;
(cmd_msg != NULL) && (cmd_msg->cmd->msg->framenum != cmd->msg->framenum);
cmd_msg = cmd_msg->next) {
if (cmd_msg->cmd->type == cmd->type)
return TRUE;
}
return FALSE;
}
break;
default:
return FALSE;
break;
}
}
static gboolean
megacostat_had_request(const gcp_cmd_t* cmd)
{
switch (cmd->type) {
GCP_CMD_REPLY_CASE
{
gcp_cmd_msg_t *cmd_msg;
/* cycle through commands to find a request in the transaction */
for (cmd_msg = cmd->trx->cmds;
(cmd_msg != NULL) && (cmd_msg->cmd->msg->framenum != cmd->msg->framenum);
cmd_msg = cmd_msg->next) {
switch (cmd_msg->cmd->type) {
GCP_CMD_REQ_CASE
return TRUE;
break;
default:
return FALSE;
break;
}
}
return FALSE;
}
break;
default:
return FALSE;
break;
}
}
static void
megacostat_filtercheck(const char *opt_arg _U_, const char **filter _U_, char** err)
{
pref_t *megaco_ctx_track, *h248_ctx_track;
megaco_ctx_track = prefs_find_preference(prefs_find_module("megaco"), "ctx_info");
h248_ctx_track = prefs_find_preference(prefs_find_module("h248"), "ctx_info");
if (!megaco_ctx_track || !h248_ctx_track) {
/* No such preferences */
return;
}
if (!prefs_get_bool_value(megaco_ctx_track, pref_current) || !prefs_get_bool_value(h248_ctx_track, pref_current)) {
*err = ws_strdup_printf("Track Context option at Protocols -> MEGACO and Protocols -> H248 preferences\n"
"has to be set to true to enable measurement of service response times.\n");
}
}
static tap_packet_status
megacostat_packet(void *pms, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pmi, tap_flags_t flags _U_)
{
rtd_data_t* rtd_data = (rtd_data_t*)pms;
rtd_stat_table* ms = &rtd_data->stat_table;
const gcp_cmd_t *mi=(const gcp_cmd_t*)pmi;
nstime_t delta;
tap_packet_status ret = TAP_PACKET_DONT_REDRAW;
switch (mi->type) {
GCP_CMD_REQ_CASE
if(!mi->trx->initial) {
/* Track Context is probably disabled, we cannot
* measure service response time */
return TAP_PACKET_DONT_REDRAW;
}
else if(mi->trx->initial->framenum != mi->msg->framenum){
/* Duplicate is ignored */
ms->time_stats[0].req_dup_num++;
}
else {
ms->time_stats[0].open_req_num++;
}
break;
GCP_CMD_REPLY_CASE
if(megacostat_is_duplicate_reply(mi)){
/* Duplicate is ignored */
ms->time_stats[0].rsp_dup_num++;
}
else if (!megacostat_had_request(mi)) {
/* no request was seen */
ms->time_stats[0].disc_rsp_num++;
}
else {
ms->time_stats[0].open_req_num--;
/* calculate time delta between request and response */
nstime_delta(&delta, &pinfo->abs_ts, &mi->trx->initial->frametime);
switch(mi->type) {
case GCP_CMD_ADD_REPLY:
time_stat_update(&(ms->time_stats[0].rtd[0]),&delta, pinfo);
break;
case GCP_CMD_MOVE_REPLY:
time_stat_update(&(ms->time_stats[0].rtd[1]),&delta, pinfo);
break;
case GCP_CMD_MOD_REPLY:
time_stat_update(&(ms->time_stats[0].rtd[2]),&delta, pinfo);
break;
case GCP_CMD_SUB_REPLY:
time_stat_update(&(ms->time_stats[0].rtd[3]),&delta, pinfo);
break;
case GCP_CMD_AUDITCAP_REPLY:
time_stat_update(&(ms->time_stats[0].rtd[4]),&delta, pinfo);
break;
case GCP_CMD_AUDITVAL_REPLY:
time_stat_update(&(ms->time_stats[0].rtd[5]),&delta, pinfo);
break;
case GCP_CMD_NOTIFY_REPLY:
time_stat_update(&(ms->time_stats[0].rtd[6]),&delta, pinfo);
break;
case GCP_CMD_SVCCHG_REPLY:
time_stat_update(&(ms->time_stats[0].rtd[7]),&delta, pinfo);
break;
case GCP_CMD_TOPOLOGY_REPLY:
time_stat_update(&(ms->time_stats[0].rtd[8]),&delta, pinfo);
break;
case GCP_CMD_REPLY:
time_stat_update(&(ms->time_stats[0].rtd[9]),&delta, pinfo);
break;
default:
time_stat_update(&(ms->time_stats[0].rtd[11]),&delta, pinfo);
}
time_stat_update(&(ms->time_stats[0].rtd[10]),&delta, pinfo);
ret = TAP_PACKET_REDRAW;
}
break;
default:
break;
}
return ret;
}
/* Call the export PDU tap with relevant data */
static void
export_megaco_pdu(packet_info *pinfo, tvbuff_t *tvb)
{
exp_pdu_data_t *exp_pdu_data = export_pdu_create_common_tags(pinfo, "megaco", EXP_PDU_TAG_PROTO_NAME);
exp_pdu_data->tvb_captured_length = tvb_captured_length(tvb);
exp_pdu_data->tvb_reported_length = tvb_reported_length(tvb);
exp_pdu_data->pdu_tvb = tvb;
tap_queue_packet(exported_pdu_tap, pinfo, exp_pdu_data);
}
/*
* The various functions that either dissect some
* subpart of MEGACO. These aren't really proto dissectors but they
* are written in the same style.
*
*/
static void
dissect_megaco_descriptors(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, gint tvb_descriptors_start_offset, gint tvb_descriptors_end_offset, proto_tree *top_tree, guint32 context);
static void
dissect_megaco_digitmapdescriptor(tvbuff_t *tvb, proto_tree *tree, gint tvb_RBRKT, gint tvb_previous_offset);
static void
dissect_megaco_topologydescriptor(tvbuff_t *tvb, proto_tree *tree, gint tvb_RBRKT, gint tvb_previous_offset);
static void
dissect_megaco_errordescriptor(tvbuff_t *tvb, packet_info* pinfo, proto_tree *tree, gint tvb_RBRKT, gint tvb_previous_offset);
static void
dissect_megaco_TerminationStatedescriptor(tvbuff_t *tvb, proto_tree *tree, gint tvb_next_offset, gint tvb_current_offset);
static void
dissect_megaco_LocalRemotedescriptor(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, gint tvb_next_offset, gint tvb_current_offset, guint32 context, gboolean is_local);
static void
dissect_megaco_LocalControldescriptor(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, gint tvb_next_offset, gint tvb_current_offset, proto_tree *top_tree);
static void
dissect_megaco_Packagesdescriptor(tvbuff_t *tvb, proto_tree *tree, gint tvb_next_offset, gint tvb_current_offset);
static void
tvb_raw_text_add(tvbuff_t *tvb, proto_tree *tree);
static int
dissect_megaco_text(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data);
static gint
megaco_tvb_find_token(tvbuff_t *tvb, gint offset, gint maxlength);
static dissector_handle_t data_handle;
static dissector_handle_t sdp_handle;
static dissector_handle_t h245_handle;
static dissector_handle_t h248_handle;
static dissector_handle_t h248_otp_handle;
static gboolean keep_persistent_data = FALSE;
/*
* dissect_megaco_text over TCP, there will be a TPKT header there
*
*/
static int dissect_megaco_text_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
int lv_tpkt_len;
/* This code is copied from the Q.931 dissector, some parts skipped.
* Check whether this looks like a TPKT-encapsulated
* MEGACO packet.
*
* The minimum length of a MEGACO message is 6?:
* Re-assembly ?
*/
lv_tpkt_len = is_tpkt(tvb, 6);
if (lv_tpkt_len == -1) {
/*
* It's not a TPKT packet;
* Is in MEGACO ?
*/
dissect_megaco_text(tvb, pinfo, tree, data);
}
dissect_tpkt_encap(tvb, pinfo, tree, TRUE,
megaco_text_handle);
return tvb_captured_length(tvb);
}
#define ERRORTOKEN 1
#define TRANSTOKEN 2
#define REPLYTOKEN 3
#define PENDINGTOKEN 4
#define RESPONSEACKTOKEN 5
typedef struct {
const char *name;
const char *compact_name;
} megaco_tokens_t;
static const megaco_tokens_t megaco_messageBody_names[] = {
{ "Unknown-token", NULL }, /* 0 Pad so that the real headers start at index 1 */
{ "Error", "ER" }, /* 1 */
{ "Transaction", "T" }, /* 2 */
{ "Reply", "P" }, /* 3 */
{ "Pending", "PN" }, /* 4 */
{ "TransactionResponseAck", "K" }, /* 5 */
};
/* Returns index of megaco_tokens_t */
static gint find_megaco_messageBody_names(tvbuff_t *tvb, int offset, guint header_len)
{
guint i;
for (i = 1; i < array_length(megaco_messageBody_names); i++) {
if (header_len == strlen(megaco_messageBody_names[i].name) &&
tvb_strncaseeql(tvb, offset, megaco_messageBody_names[i].name, header_len) == 0)
return i;
if (megaco_messageBody_names[i].compact_name != NULL &&
header_len == strlen(megaco_messageBody_names[i].compact_name) &&
tvb_strncaseeql(tvb, offset, megaco_messageBody_names[i].compact_name, header_len) == 0)
return i;
}
return -1;
}
static proto_item *
megaco_tree_add_string(proto_tree *tree, int hfindex, tvbuff_t *tvb,
gint start, gint length, const char *value)
{
proto_item *pi;
pi = proto_tree_add_string(tree, hfindex, tvb, start, length, value);
if (!global_megaco_dissect_tree) {
proto_item_set_hidden(pi);
}
return(pi);
}
static proto_item *
my_proto_tree_add_uint(proto_tree *tree, int hfindex, tvbuff_t *tvb,
gint start, gint length, guint32 value)
{
proto_item *pi;
pi = proto_tree_add_uint(tree, hfindex, tvb, start, 1, value);
/* String length may be longer than FT_UINT will allow */
proto_item_set_len(pi, length);
if (!global_megaco_dissect_tree) {
proto_item_set_hidden(pi);
}
return(pi);
}
/*
* dissect_megaco_text - The dissector for the MEGACO Protocol, using
* text encoding.
*/
static int
dissect_megaco_text(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
gint tvb_len, len;
gint tvb_offset,tvb_current_offset,tvb_previous_offset,tvb_next_offset,tokenlen;
gint context_offset, context_length, save_offset, save_length;
gint tvb_command_start_offset, tvb_command_end_offset;
gint tvb_descriptors_start_offset, tvb_descriptors_end_offset;
gint tvb_transaction_end_offset;
proto_tree *megaco_tree, *message_body_tree, *megaco_tree_command_line, *ti, *sub_ti;
guint8 word[15];
guint8 TermID[30];
guint8 tempchar;
gint tvb_RBRKT, tvb_LBRKT, RBRKT_counter, LBRKT_counter;
guint token_index=0;
guint32 dword;
guchar needle;
gcp_msg_t *msg = NULL;
gcp_trx_t *trx = NULL;
gcp_ctx_t *ctx = NULL;
gcp_cmd_t *cmd = NULL;
gcp_term_t *term = NULL;
gcp_trx_type_t trx_type = GCP_TRX_NONE;
guint32 trx_id = 0, pending_id;
guint32 ctx_id = 0;
gcp_cmd_type_t cmd_type = GCP_CMD_NONE;
gcp_wildcard_t wild_term = GCP_WILDCARD_NONE;
gboolean short_form;
megaco_commands_enum_t megaco_command = MEGACO_CMD_NOT_SET;
/* Initialize variables */
tvb_len = tvb_reported_length(tvb);
megaco_tree = NULL;
ti = NULL;
tvb_offset = 0;
RBRKT_counter = 0;
LBRKT_counter = 0;
/* Check if H.248 in otp(Erlang) internal format
* XXX Needs improvement?
* Ref:
* http://www.erlang.org/doc/apps/megaco/part_frame.html
* 4.1 Internal form of messages
* 4.2 The different encodings
*/
dword = tvb_get_ntoh24(tvb,0);
if ((dword == 0x836803)&&(h248_otp_handle)){
call_dissector(h248_otp_handle, tvb, pinfo, tree);
return tvb_captured_length(tvb);
}
msg = gcp_msg(pinfo, tvb_raw_offset(tvb), keep_persistent_data);
/*
* Check to see whether we're really dealing with MEGACO by looking
* for the "MEGACO" string or a "!".This needs to be improved when supporting
* binary encodings. Bugfix add skipping of leading spaces.
*/
tvb_offset = megaco_tvb_skip_wsp(tvb, tvb_offset);
/* Quick fix for MEGACO not following the RFC, hopefully not breaking any thing
* Turned out to be TPKT in case of TCP, added some code to handle that.
*
* tvb_offset = tvb_find_guint8(tvb, tvb_offset, 5, 'M');
*/
if(!tvb_get_nstringz0(tvb,tvb_offset,sizeof(word),word)) return tvb_captured_length(tvb);
/* Quick fix for MEGACO packet with Authentication Header,
* marked as "AU" or "Authentication".
*/
if ((g_ascii_strncasecmp(word, "Authentication", 14) == 0) ||
(g_ascii_strncasecmp(word, "AU", 2) == 0)) {
gint counter;
guint8 next;
/* move offset to end of auth header (EOL or WSP) */
for ( counter = tvb_offset; counter < tvb_len; counter++ ) {
needle = tvb_get_guint8(tvb, counter);
if (needle == ' ' || needle == '\r' || needle == '\n') {
next = tvb_get_guint8(tvb, counter+1);
if (next == ' ' || next == '\r' || next == '\n') {
continue;
}
tvb_offset = counter + 1;
break;
}
}
}
short_form = (tvb_get_guint8(tvb, tvb_offset ) == '!');
if (g_ascii_strncasecmp(word, "MEGACO", 6) != 0 && !short_form){
gint8 ber_class;
gboolean pc;
gint32 tag;
dissector_handle_t handle = data_handle;
get_ber_identifier(tvb, 0, &ber_class, &pc, &tag);
if (ber_class == BER_CLASS_UNI && pc && tag == BER_UNI_TAG_SEQUENCE ) {
handle = h248_handle;
}
call_dissector(handle,tvb,pinfo,tree);
return tvb_captured_length(tvb);
}
/* Display MEGACO in protocol column */
col_set_str(pinfo->cinfo, COL_PROTOCOL, "MEGACO");
/* Report this packet to the tap */
if (!pinfo->flags.in_error_pkt) {
if (have_tap_listener(exported_pdu_tap)) {
export_megaco_pdu(pinfo, tvb);
}
}
/* Build the info tree if we've been given a root */
/* Create megaco subtree */
ti = proto_tree_add_item(tree,proto_megaco,tvb, 0, -1, ENC_NA);
megaco_tree = proto_item_add_subtree(ti, ett_megaco);
/* Format of 'message' is = MegacopToken SLASH Version SEP mId SEP messageBody */
/* MegacopToken = "MEGACO" or "!" */
/* According to H248.1-200205 Annex B Text encoding ( protocol version 2 ) */
/* Find version */
tvb_previous_offset = tvb_find_guint8(tvb, 0,
tvb_len, '/');
if (tvb_previous_offset == -1) {
expert_add_info_format(pinfo, ti, &ei_megaco_parse_error,
"Sorry, no \"/\" in the MEGACO header, I can't parse this packet");
return tvb_captured_length(tvb);
}
megaco_tree_add_string(megaco_tree, hf_megaco_start, tvb, 0, tvb_previous_offset+1,
tvb_get_string_enc(wmem_packet_scope(), tvb, 0, tvb_previous_offset, ENC_UTF_8|ENC_NA));
/* skip / */
tvb_previous_offset++;
/* assume at least one digit in version */
tvb_current_offset = tvb_previous_offset + 1;
if (g_ascii_isdigit(tvb_get_guint8(tvb, tvb_current_offset))) {
/* 2-digit version */
tvb_current_offset++;
}
megaco_tree_add_string(megaco_tree, hf_megaco_version, tvb, tvb_previous_offset, tvb_current_offset - tvb_previous_offset,
tvb_get_string_enc(wmem_packet_scope(), tvb, tvb_previous_offset, tvb_current_offset - tvb_previous_offset, ENC_UTF_8|ENC_NA));
tvb_previous_offset = tvb_current_offset;
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_previous_offset);
if (tvb_previous_offset == tvb_current_offset) {
expert_add_info_format(pinfo, ti, &ei_megaco_parse_error,
"[ Parse error: missing SEP in MEGACO header ]");
return tvb_current_offset;
}
tvb_previous_offset = tvb_current_offset;
/* mId should follow here,
* mId = (( domainAddress / domainName ) [":" portNumber]) / mtpAddress / deviceName
* domainAddress = "[" (IPv4address / IPv6address) "]"
* domainName = "<" (ALPHA / DIGIT) *63(ALPHA / DIGIT / "-" /".") ">"
* mtpAddress = MTPToken LBRKT 4*8 (HEXDIG) RBRKT
* MTPToken = ("MTP")
* deviceName = pathNAME
* pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )["@" pathDomainName ]
*/
tvb_current_offset = tvb_ws_mempbrk_pattern_guint8(tvb, tvb_current_offset, -1, &pbrk_whitespace, &needle);
if (tvb_current_offset == -1) {
expert_add_info_format(pinfo, ti, &ei_megaco_parse_error,
"[ Parse error: no body in MEGACO message (missing SEP after mId) ]");
return tvb_captured_length(tvb);
}
tvb_next_offset = megaco_tvb_skip_wsp(tvb, tvb_current_offset);
/* At this point we should point to the "\n" ending the mId element
* or to the next character after white space SEP
*/
megaco_tree_add_string(megaco_tree, hf_megaco_mId, tvb, tvb_previous_offset, tvb_current_offset - tvb_previous_offset,
tvb_get_string_enc(wmem_packet_scope(), tvb, tvb_previous_offset, tvb_current_offset - tvb_previous_offset, ENC_UTF_8|ENC_NA));
col_clear(pinfo->cinfo, COL_INFO);
do{
tvb_previous_offset = tvb_next_offset;
/* Next part is
* : messageBody = ( errorDescriptor / transactionList )
* errorDescriptor = ErrorToken EQUAL ErrorCode LBRKT [quotedString] RBRKT
* ErrorToken = ("Error" / "ER")
*
* transactionList = 1*( transactionRequest / transactionReply /
* transactionPending / transactionResponseAck )
*
* transactionResponseAck = ResponseAckToken LBRKT
* transactionAck*(COMMA transactionAck) RBRKT
* ResponseAckToken = ("TransactionResponseAck"/ "K")
*
* transactionPending = PendingToken EQUAL TransactionID LBRKT RBRKT
* PendingToken = ("Pending" / "PN")
*
* transactionReply = ReplyToken EQUAL TransactionID LBRKT
* [ ImmAckRequiredToken COMMA]( errorDescriptor / actionReplyList ) RBRKT
* ReplyToken = ("Reply" / "P")
*
* transactionRequest = TransToken EQUAL TransactionID LBRKT
* actionRequest *(COMMA actionRequest) RBRKT
* TransToken = ("Transaction" / "T")
*/
/* Find token length */
for (tvb_offset=tvb_previous_offset; tvb_offset < tvb_len-1; tvb_offset++){
if (!g_ascii_isalpha(tvb_get_guint8(tvb, tvb_offset ))){
break;
}
}
tokenlen = tvb_offset - tvb_previous_offset;
token_index = find_megaco_messageBody_names(tvb, tvb_previous_offset, tokenlen);
/* Debug code
ws_warning("token_index %u",token_index);
*/
tvb_LBRKT = tvb_find_guint8(tvb, tvb_offset, tvb_len, '{');
tvb_current_offset = tvb_LBRKT;
tvb_transaction_end_offset = megaco_tvb_find_token(tvb, tvb_LBRKT - 1, tvb_len);
switch ( token_index ){
/* errorDescriptor */
case ERRORTOKEN:
col_set_str(pinfo->cinfo, COL_INFO, "Error ");
tvb_current_offset = megaco_tvb_find_token(tvb, tvb_offset, tvb_len); /*tvb_find_guint8(tvb, tvb_offset+1, tvb_len, '}');*/
ti = proto_tree_add_format_text(megaco_tree, tvb, tvb_previous_offset, tvb_current_offset-tvb_previous_offset);
message_body_tree = proto_item_add_subtree(ti, ett_megaco_message_body);
if (tree) {
megaco_tree_add_string(message_body_tree, hf_megaco_transaction, tvb,
tvb_previous_offset, tokenlen,
"Error" );
tvb_command_start_offset = tvb_previous_offset;
dissect_megaco_errordescriptor(tvb, pinfo, megaco_tree, tvb_len-1, tvb_command_start_offset);
}
return tvb_captured_length(tvb);
/* transactionResponseAck
* transactionResponseAck = ResponseAckToken LBRKT transactionAck
* *(COMMA transactionAck) RBRKT
* transactionAck = transactionID / (transactionID "-" transactionID)
*/
case RESPONSEACKTOKEN:
tvb_LBRKT = tvb_find_guint8(tvb, tvb_offset, tvb_transaction_end_offset, '{');
tvb_offset = tvb_LBRKT;
save_offset = tvb_previous_offset;
save_length = tvb_current_offset-tvb_previous_offset;
megaco_tree_add_string(megaco_tree, hf_megaco_transaction, tvb,
save_offset, save_length, "TransactionResponseAck" );
tvb_previous_offset = megaco_tvb_skip_wsp(tvb, tvb_offset+1);
tvb_current_offset = tvb_find_guint8(tvb, tvb_offset+1, tvb_len, '}');
/*tvb_current_offset = megaco_tvb_find_token(tvb, tvb_offset, tvb_transaction_end_offset);*/
tvb_current_offset = megaco_tvb_skip_wsp_return(tvb, tvb_current_offset)-1; /* cut last RBRKT */
len = tvb_current_offset - tvb_previous_offset;
pending_id = (guint)strtoul(tvb_format_text(pinfo->pool, tvb,tvb_previous_offset,len),NULL,10);
col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "%d TransactionResponseAck", pending_id);
my_proto_tree_add_uint(megaco_tree, hf_megaco_transid, tvb, save_offset, save_length, pending_id);
if(global_megaco_raw_text){
tvb_raw_text_add(tvb, megaco_tree);
}
return tvb_captured_length(tvb);
/* Pe and PN is transactionPending, P+"any char" is transactionReply */
case PENDINGTOKEN:
tvb_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_transaction_end_offset, '=')+1;
tvb_offset = megaco_tvb_skip_wsp(tvb, tvb_offset);
tvb_LBRKT = tvb_find_guint8(tvb, tvb_offset, tvb_transaction_end_offset, '{');
tvb_current_offset = tvb_LBRKT;
save_offset = tvb_previous_offset;
save_length = tvb_current_offset-tvb_previous_offset;
megaco_tree_add_string(megaco_tree, hf_megaco_transaction, tvb,
save_offset, save_length, "Reply" );
tvb_current_offset = megaco_tvb_skip_wsp_return(tvb, tvb_current_offset-1);
len = tvb_current_offset - tvb_offset;
pending_id = (guint)strtoul(tvb_format_text(pinfo->pool, tvb,tvb_offset,len),NULL,10);
col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "%d Pending", pending_id);
my_proto_tree_add_uint(megaco_tree, hf_megaco_transid, tvb, save_offset, save_length, pending_id);
return tvb_captured_length(tvb);
/* transactionReply */
case REPLYTOKEN:
trx_type = GCP_TRX_REPLY;
tvb_LBRKT = tvb_find_guint8(tvb, tvb_offset, tvb_transaction_end_offset, '{');
save_offset = tvb_previous_offset;
save_length = tvb_LBRKT-tvb_previous_offset;
megaco_tree_add_string(megaco_tree, hf_megaco_transaction, tvb,
save_offset, save_length, "Reply" );
tvb_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_transaction_end_offset, '=')+1;
tvb_offset = megaco_tvb_skip_wsp(tvb, tvb_offset);
tvb_current_offset = megaco_tvb_skip_wsp_return(tvb, tvb_LBRKT-1);
len = tvb_current_offset - tvb_offset;
trx_id = (guint)strtoul(tvb_format_text(pinfo->pool, tvb,tvb_offset,len),NULL,10);
col_add_fstr(pinfo->cinfo, COL_INFO, "%d Reply ", trx_id);
my_proto_tree_add_uint(megaco_tree, hf_megaco_transid, tvb, save_offset, save_length, trx_id);
/* Find if we have a errorDescriptor or actionReplyList */
tvb_offset = megaco_tvb_skip_wsp(tvb, tvb_LBRKT+1);
tempchar = tvb_get_guint8(tvb,tvb_offset);
if ((tempchar == 'E')||(tempchar == 'e')){
dissect_megaco_errordescriptor(tvb, pinfo, megaco_tree, tvb_transaction_end_offset-1, tvb_offset);
return tvb_captured_length(tvb);
}
/* Offset should be at first printable char after { */
tvb_previous_offset = tvb_offset;
break;
case TRANSTOKEN:
/* TransactionRequest */
trx_type = GCP_TRX_REQUEST;
save_offset = tvb_previous_offset;
save_length = tvb_current_offset-tvb_previous_offset;
megaco_tree_add_string(megaco_tree, hf_megaco_transaction, tvb,
save_offset, save_length, "Request" );
tvb_offset = tvb_find_guint8(tvb, tvb_offset, tvb_transaction_end_offset, '=')+1;
tvb_offset = megaco_tvb_skip_wsp(tvb, tvb_offset);
tvb_current_offset = megaco_tvb_skip_wsp_return(tvb, tvb_current_offset-1);
len = tvb_current_offset - tvb_offset;
trx_id = (guint)strtoul(tvb_format_text(pinfo->pool, tvb,tvb_offset,len),NULL,10);
col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "%d Request", trx_id);
my_proto_tree_add_uint(megaco_tree, hf_megaco_transid, tvb, save_offset, save_length, trx_id);
/* Offset should be at first printable char after { */
tvb_previous_offset = megaco_tvb_skip_wsp(tvb, tvb_LBRKT+1);
break;
default :
proto_tree_add_expert_format(tree, pinfo, &ei_megaco_error_descriptor_transaction_list, tvb, 0, -1,
"Sorry, can't understand errorDescriptor / transactionList = %s, can't parse it pos %u",
tvb_format_text(pinfo->pool, tvb,tvb_previous_offset,2),tvb_previous_offset);
return tvb_captured_length(tvb);
} /* end switch */
/* Only these remains now
* transactionReply = ReplyToken EQUAL TransactionID LBRKT
* [ ImmAckRequiredToken COMMA]( errorDescriptor / actionReplyList ) RBRKT
* ReplyToken = ("Reply" / "P")
*
* errorDescriptor = ErrorToken EQUAL ErrorCode
* LBRKT [quotedString] RBRKT
*
* transactionRequest = TransToken EQUAL TransactionID LBRKT
* actionRequest *(COMMA actionRequest) RBRKT
* TransToken = ("Transaction" / "T")
*/
trx = gcp_trx(msg , trx_id , trx_type, pinfo, keep_persistent_data);
/* Find Context */
nextcontext:
tvb_next_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_transaction_end_offset, '{');
context_offset = tvb_previous_offset;
context_length = tvb_next_offset-tvb_previous_offset+1;
tvb_previous_offset = tvb_find_guint8(tvb, tvb_current_offset, tvb_transaction_end_offset, '=')+1;
tvb_previous_offset = megaco_tvb_skip_wsp(tvb, tvb_previous_offset);
if (tvb_current_offset >= tvb_next_offset) {
proto_tree_add_expert_format(megaco_tree, pinfo, &ei_megaco_parse_error,
tvb, context_offset, context_length, "Parse error: Invalid offset");
return tvb_captured_length(tvb);
}
tvb_current_offset = tvb_next_offset;
tokenlen = tvb_current_offset - tvb_previous_offset;
tempchar = tvb_get_guint8(tvb, tvb_previous_offset );
if (tvb_get_guint8(tvb, tvb_current_offset-1 ) == ' '){
tokenlen--;
}
switch ( tempchar ){
case '$':
ctx_id = CHOOSE_CONTEXT;
break;
case '*':
ctx_id = ALL_CONTEXTS;
break;
case '-':
ctx_id = NULL_CONTEXT;
break;
default:
ctx_id = (guint)strtoul(tvb_format_text(pinfo->pool, tvb, tvb_previous_offset, tokenlen),NULL,10);
}
my_proto_tree_add_uint(megaco_tree, hf_megaco_Context, tvb, context_offset, context_length, ctx_id);
col_append_fstr(pinfo->cinfo, COL_INFO, " |=%s", val_to_str(ctx_id, megaco_context_vals, "%d"));
ctx = gcp_ctx(msg,trx,ctx_id,pinfo,keep_persistent_data);
/* Find Commands */
/* If Transaction is Request, Reply or Pending */
tvb_command_start_offset = megaco_tvb_skip_wsp(tvb, tvb_current_offset +1);
tvb_command_end_offset = tvb_command_start_offset;
tvb_LBRKT = tvb_command_start_offset;
tvb_RBRKT = tvb_command_start_offset;
/* The following loop find the individual contexts, commands and call the for every Descriptor a subroutine */
do {
tvb_command_end_offset = tvb_find_guint8(tvb, tvb_command_end_offset +1,
tvb_transaction_end_offset, ',');
if ( tvb_command_end_offset == -1 || tvb_command_end_offset > tvb_transaction_end_offset){
tvb_command_end_offset = tvb_transaction_end_offset ;
}
/* checking how many left brackets are before the next comma */
while ( tvb_find_guint8(tvb, tvb_LBRKT+1,tvb_transaction_end_offset, '{') != -1
&& (tvb_find_guint8(tvb, tvb_LBRKT+1,tvb_transaction_end_offset, '{') < tvb_command_end_offset)){
tvb_LBRKT = tvb_find_guint8(tvb, tvb_LBRKT+1,
tvb_transaction_end_offset, '{');
LBRKT_counter++;
}
/* checking how many right brackets are before the next comma */
while ( (tvb_find_guint8(tvb, tvb_RBRKT+1,tvb_transaction_end_offset, '}') != -1 )
&& (tvb_find_guint8(tvb, tvb_RBRKT+1,tvb_transaction_end_offset, '}') <= tvb_command_end_offset)
&& LBRKT_counter != 0){
tvb_RBRKT = tvb_find_guint8(tvb, tvb_RBRKT+1,
tvb_transaction_end_offset, '}');
RBRKT_counter++;
}
/* If equal or more right brackets before the comma, one command is complete */
if ( LBRKT_counter <= RBRKT_counter ){
tvb_current_offset = tvb_find_guint8(tvb, tvb_command_start_offset,
tvb_transaction_end_offset, '{');
/* includes no descriptors */
if ( LBRKT_counter == 0 ){
tvb_current_offset = tvb_command_end_offset;
/* the last command in a context */
if ( tvb_find_guint8(tvb, tvb_command_start_offset, tvb_transaction_end_offset, '}') < tvb_current_offset
&& tvb_find_guint8(tvb, tvb_command_start_offset, tvb_transaction_end_offset, '}') != -1){
tvb_previous_offset = tvb_find_guint8(tvb, tvb_command_start_offset,
tvb_transaction_end_offset, '}');
len = tvb_previous_offset - tvb_command_start_offset;
tvb_previous_offset = megaco_tvb_skip_wsp_return(tvb, tvb_previous_offset -1);
tokenlen = tvb_previous_offset - tvb_command_start_offset;
}
/* not the last command in a context*/
else{
len = tvb_current_offset - tvb_command_start_offset;
tvb_current_offset = megaco_tvb_skip_wsp_return(tvb, tvb_current_offset -1);
tokenlen = tvb_current_offset - tvb_command_start_offset;
}
}
/* command includes descriptors */
else{
len = tvb_current_offset - tvb_command_start_offset;
tvb_current_offset = megaco_tvb_skip_wsp_return(tvb, tvb_current_offset -1);
tokenlen = tvb_current_offset - tvb_command_start_offset;
}
/* if a next context is specified */
if ( tvb_get_guint8(tvb, tvb_command_start_offset ) == 'C'){
tvb_current_offset = tvb_command_start_offset;
tvb_previous_offset = tvb_command_start_offset;
LBRKT_counter = 0;
RBRKT_counter = 0;
goto nextcontext;
}
megaco_tree_command_line = proto_tree_add_subtree(megaco_tree, tvb, tvb_command_start_offset, len+1, ett_megaco_command_line, &sub_ti, "Command: ");
megaco_command = MEGACO_CMD_NOT_SET;
/* creation of the megaco_tree_command_line additionally Command and Transaction ID will be printed in this line */
/* Changed to use the lines above. this code is saved if there is complaints
sub_ti = proto_tree_add_item(megaco_tree,hf_megaco_command_line,tvb,tvb_command_start_offset,tokenlen, ENC_UTF_8);
megaco_tree_command_line = proto_item_add_subtree(sub_ti, ett_megaco_command_line);
*/
if (!global_megaco_dissect_tree) {
proto_item_set_hidden(sub_ti);
}
tvb_next_offset = tvb_command_start_offset + tokenlen;
/* Try to dissect Topology Descriptor before the command */
tempchar = tvb_get_guint8(tvb, tvb_command_start_offset);
if ( (tempchar >= 'a')&& (tempchar <= 'z')){
tempchar = tempchar - 0x20;
}
if ( tempchar == 'T') {
tempchar = tvb_get_guint8(tvb, tvb_command_start_offset+1);
if ( (tempchar >= 'a')&& (tempchar <= 'z'))
tempchar = tempchar - 0x20;
if ( tempchar == 'P' || tempchar == 'O'){
gint tvb_topology_end_offset = tvb_find_guint8(tvb, tvb_command_start_offset, tvb_transaction_end_offset, '}');
if ( tvb_topology_end_offset == -1 ){
expert_add_info_format(pinfo, sub_ti, &ei_megaco_parse_error, "Parse error: Missing \"}\"");
return tvb_captured_length(tvb);
}
tvb_command_start_offset = tvb_find_guint8(tvb, tvb_command_start_offset, tvb_transaction_end_offset, '{');
if ( tvb_command_start_offset == -1 ){
expert_add_info_format(pinfo, sub_ti, &ei_megaco_parse_error, "Parse error: Missing \"{\"");
return tvb_captured_length(tvb);
}
dissect_megaco_topologydescriptor(tvb, megaco_tree_command_line, tvb_topology_end_offset-1, tvb_command_start_offset+1);
/* Command after Topology Descriptor */
tvb_command_start_offset = tvb_find_guint8(tvb, tvb_topology_end_offset + 1,
tvb_transaction_end_offset, ',');
if ( tvb_command_start_offset == -1 ){
/* No Command present after Topology Descriptor */
break;
} else {
/* Try to find the first char of the command */
tvb_command_start_offset = megaco_tvb_skip_wsp(tvb, tvb_command_start_offset + 1);
RBRKT_counter = 0;
LBRKT_counter = 0;
tvb_LBRKT = tvb_command_start_offset;
tvb_RBRKT = tvb_command_start_offset;
/*tvb_next_offset = tvb_find_guint8(tvb, tvb_command_start_offset, tvb_transaction_end_offset, '{');*/
continue;
}
}
}
/* Additional value */
if ( tvb_get_guint8(tvb, tvb_command_start_offset ) == 'O'){
proto_tree_add_item(megaco_tree_command_line, hf_megaco_command_optional, tvb, tvb_command_start_offset, 2, ENC_NA);
tvb_command_start_offset = tvb_command_start_offset+2;
}
/* Additional value */
if ( tvb_get_guint8(tvb, tvb_command_start_offset ) == 'W'){
proto_tree_add_item(megaco_tree_command_line, hf_megaco_wildcard_response, tvb, tvb_command_start_offset, 2, ENC_NA );
tvb_command_start_offset = tvb_command_start_offset+2;
}
tvb_offset = tvb_find_guint8(tvb, tvb_command_start_offset,
tvb_transaction_end_offset, '=');
if (tvb_offset == -1 ) {
proto_tree_add_expert_format(megaco_tree, pinfo, &ei_megaco_parse_error, tvb, tvb_command_start_offset, len+1, "Parse error: Missing \"=\"");
return tvb_captured_length(tvb);
}
tvb_offset = megaco_tvb_skip_wsp_return(tvb, tvb_offset -1);
tokenlen = tvb_offset - tvb_command_start_offset;
tempchar = tvb_get_guint8(tvb, tvb_command_start_offset);
if ( (tempchar >= 'a')&& (tempchar <= 'z'))
tempchar = tempchar - 0x20;
if ( tempchar != 'E' ){
/* Short form used */
if (short_form){
switch ( tempchar ){
case 'A':
tempchar = tvb_get_guint8(tvb, tvb_command_start_offset+1);
if ( (tempchar >= 'a')&& (tempchar <= 'z'))
tempchar = tempchar - 0x20;
switch ( tempchar ){
case 'V':
switch(trx_type) {
case GCP_TRX_REQUEST: cmd_type = GCP_CMD_AUDITVAL_REPLY; break;
case GCP_TRX_REPLY: cmd_type = GCP_CMD_AUDITVAL_REQ; break;
default: cmd_type = GCP_CMD_NONE; break;
}
proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
tvb_command_start_offset, tokenlen, "AuditValue");
col_append_str(pinfo->cinfo, COL_INFO, " AuditValue");
proto_item_append_text(sub_ti, "AuditValue");
break;
case 'C':
switch(trx_type) {
case GCP_TRX_REQUEST: cmd_type = GCP_CMD_AUDITCAP_REQ; break;
case GCP_TRX_REPLY: cmd_type = GCP_CMD_AUDITCAP_REPLY; break;
default: cmd_type = GCP_CMD_NONE; break;
}
proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
tvb_command_start_offset, tokenlen, "AuditCapability");
col_append_str(pinfo->cinfo, COL_INFO, " AuditCapability");
proto_item_append_text(sub_ti, "AuditCapability");
break;
default:
switch(trx_type) {
case GCP_TRX_REQUEST: cmd_type = GCP_CMD_ADD_REQ; break;
case GCP_TRX_REPLY: cmd_type = GCP_CMD_ADD_REPLY; break;
default: cmd_type = GCP_CMD_NONE; break;
}
proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
tvb_command_start_offset, tokenlen, "Add");
col_append_str(pinfo->cinfo, COL_INFO, " Add");
proto_item_append_text(sub_ti, "Add");
break;
}
break;
case 'I':
/* "IEPS" */
tempchar = tvb_get_guint8(tvb, tvb_command_start_offset+1);
if(tempchar == 'E'){
proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
tvb_command_start_offset, tokenlen, "IEPSCall");
col_append_str(pinfo->cinfo, COL_INFO, " IEPSCall");
proto_item_append_text(sub_ti, "IEPSCall");
}
cmd_type = GCP_CMD_NONE;
break;
case 'N':
switch(trx_type) {
case GCP_TRX_REQUEST: cmd_type = GCP_CMD_NOTIFY_REQ; break;
case GCP_TRX_REPLY: cmd_type = GCP_CMD_NOTIFY_REPLY; break;
default: cmd_type = GCP_CMD_NONE; break;
}
proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
tvb_command_start_offset, tokenlen, "Notify");
col_append_str(pinfo->cinfo, COL_INFO, " Notify");
proto_item_append_text(sub_ti, "Notify");
break;
case 'M':
tempchar = tvb_get_guint8(tvb, tvb_command_start_offset+1);
if ( (tempchar >= 'a')&& (tempchar <= 'z'))
tempchar = tempchar - 0x20;
switch ( tempchar ){
case 'F':
switch(trx_type) {
case GCP_TRX_REQUEST: cmd_type = GCP_CMD_MOD_REQ; break;
case GCP_TRX_REPLY: cmd_type = GCP_CMD_MOD_REPLY; break;
default: cmd_type = GCP_CMD_NONE; break;
}
proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
tvb_command_start_offset, tokenlen, "Modify");
col_append_str(pinfo->cinfo, COL_INFO, " Modify");
proto_item_append_text(sub_ti, "Modify");
break;
case 'V':
switch(trx_type) {
case GCP_TRX_REQUEST: cmd_type = GCP_CMD_MOVE_REQ; break;
case GCP_TRX_REPLY: cmd_type = GCP_CMD_MOVE_REPLY; break;
default: cmd_type = GCP_CMD_NONE; break;
}
proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
tvb_command_start_offset, tokenlen, "Move");
col_append_str(pinfo->cinfo, COL_INFO, " Move");
proto_item_append_text(sub_ti, "Move");
break;
}
break;
case 'P':
cmd_type = GCP_CMD_NONE;
/*
PackagesToken = ("Packages" / "PG")
PendingToken = ("Pending" / "PN")
PriorityToken = ("Priority" / "PR")
ProfileToken = ("Profile" / "PF")
*/
tempchar = tvb_get_guint8(tvb, tvb_command_start_offset+1);
if ( (tempchar >= 'a')&& (tempchar <= 'z'))
tempchar = tempchar - 0x20;
switch ( tempchar ){
case 'G':
proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
tvb_command_start_offset, tokenlen, "Packages");
col_append_str(pinfo->cinfo, COL_INFO, " Packages");
proto_item_append_text(sub_ti, "Packages");
break;
case 'N':
proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
tvb_command_start_offset, tokenlen, "Pending");
col_append_str(pinfo->cinfo, COL_INFO, " Pending");
proto_item_append_text(sub_ti, "Pending");
break;
case 'R':
proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
tvb_command_start_offset, tokenlen, "Priority");
col_append_str(pinfo->cinfo, COL_INFO, " Priority");
proto_item_append_text(sub_ti, "Priority");
megaco_command = MEGACO_CMD_PRIORITY;
break;
case 'F':
proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
tvb_command_start_offset, tokenlen, "Profile");
col_append_str(pinfo->cinfo, COL_INFO, " Profile");
proto_item_append_text(sub_ti, "Profile");
break;
}
break;
case 'S':
tempchar = tvb_get_guint8(tvb, tvb_command_start_offset+1);
if ( (tempchar >= 'a')&& (tempchar <= 'z'))
tempchar = tempchar - 0x20;
switch ( tempchar ){
case 'C':
switch(trx_type) {
case GCP_TRX_REQUEST: cmd_type = GCP_CMD_SVCCHG_REQ; break;
case GCP_TRX_REPLY: cmd_type = GCP_CMD_SVCCHG_REPLY; break;
default: cmd_type = GCP_CMD_NONE; break;
}
proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
tvb_command_start_offset, tokenlen, "ServiceChange");
col_append_str(pinfo->cinfo, COL_INFO, " ServiceChange");
proto_item_append_text(sub_ti, "ServiceChange");
break;
default:
switch(trx_type) {
case GCP_TRX_REQUEST: cmd_type = GCP_CMD_SUB_REQ; break;
case GCP_TRX_REPLY: cmd_type = GCP_CMD_SUB_REPLY; break;
default: cmd_type = GCP_CMD_NONE; break;
}
proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
tvb_command_start_offset, tokenlen, "Subtract");
col_append_str(pinfo->cinfo, COL_INFO, " Subtract");
proto_item_append_text(sub_ti, "Subtract");
break;
}
break;
default:
proto_item_append_text(sub_ti, "<None> 0x%02x", tempchar);
expert_add_info(pinfo, sub_ti, &ei_megaco_no_command);
return tvb_captured_length(tvb);
}
}
else{
gchar* command = tvb_format_text(pinfo->pool, tvb, tvb_command_start_offset, tokenlen);
if ( g_str_equal(command,"Subtract") ) {
switch(trx_type) {
case GCP_TRX_REQUEST: cmd_type = GCP_CMD_SUB_REQ; break;
case GCP_TRX_REPLY: cmd_type = GCP_CMD_SUB_REPLY; break;
default: cmd_type = GCP_CMD_NONE; break;
}
} else if ( g_str_equal(command,"AuditValue") ) {
switch(trx_type) {
case GCP_TRX_REQUEST: cmd_type = GCP_CMD_AUDITVAL_REPLY; break;
case GCP_TRX_REPLY: cmd_type = GCP_CMD_AUDITVAL_REQ; break;
default: cmd_type = GCP_CMD_NONE; break;
}
} else if ( g_str_equal(command,"AuditCapability") ) {
switch(trx_type) {
case GCP_TRX_REQUEST: cmd_type = GCP_CMD_AUDITCAP_REQ; break;
case GCP_TRX_REPLY: cmd_type = GCP_CMD_AUDITCAP_REPLY; break;
default: cmd_type = GCP_CMD_NONE; break;
}
} else if ( g_str_equal(command,"Add") ) {
switch(trx_type) {
case GCP_TRX_REQUEST: cmd_type = GCP_CMD_ADD_REQ; break;
case GCP_TRX_REPLY: cmd_type = GCP_CMD_ADD_REPLY; break;
default: cmd_type = GCP_CMD_NONE; break;
}
} else if ( g_str_equal(command,"Notify") ) {
switch(trx_type) {
case GCP_TRX_REQUEST: cmd_type = GCP_CMD_NOTIFY_REQ; break;
case GCP_TRX_REPLY: cmd_type = GCP_CMD_NOTIFY_REPLY; break;
default: cmd_type = GCP_CMD_NONE; break;
}
} else if ( g_str_equal(command,"Modify") ) {
switch(trx_type) {
case GCP_TRX_REQUEST: cmd_type = GCP_CMD_MOD_REQ; break;
case GCP_TRX_REPLY: cmd_type = GCP_CMD_MOD_REPLY; break;
default: cmd_type = GCP_CMD_NONE; break;
}
} else if ( g_str_equal(command,"Move") ) {
switch(trx_type) {
case GCP_TRX_REQUEST: cmd_type = GCP_CMD_MOVE_REQ; break;
case GCP_TRX_REPLY: cmd_type = GCP_CMD_MOVE_REPLY; break;
default: cmd_type = GCP_CMD_NONE; break;
}
} else if ( g_str_equal(command,"ServiceChange") ) {
switch(trx_type) {
case GCP_TRX_REQUEST: cmd_type = GCP_CMD_SVCCHG_REQ; break;
case GCP_TRX_REPLY: cmd_type = GCP_CMD_SVCCHG_REPLY; break;
default: cmd_type = GCP_CMD_NONE; break;
}
} else {
switch(trx_type) {
case GCP_TRX_REQUEST: cmd_type = GCP_CMD_OTHER_REQ; break;
case GCP_TRX_REPLY: cmd_type = GCP_CMD_REPLY; break;
default: cmd_type = GCP_CMD_NONE; break;
}
}
proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
tvb_command_start_offset, tokenlen, command);
col_append_fstr(pinfo->cinfo, COL_INFO, " %s", command);
proto_item_append_text(sub_ti, " %s", command);
}
if (cmd_type == GCP_CMD_NONE && trx_type == GCP_TRX_REPLY) {
cmd_type = GCP_CMD_REPLY;
}
if (cmd_type != GCP_CMD_NONE) {
cmd = gcp_cmd(msg, trx, ctx, cmd_type, tvb_command_start_offset, pinfo, keep_persistent_data);
tap_queue_packet(megaco_tap, pinfo, cmd);
}
tvb_offset = tvb_find_guint8(tvb, tvb_command_start_offset,
tvb_transaction_end_offset, '=');
if (tvb_offset == -1 ) {
expert_add_info_format(pinfo, sub_ti, &ei_megaco_parse_error, "Parse error: Missing \"=\"");
return tvb_captured_length(tvb);
}
tvb_offset = megaco_tvb_skip_wsp(tvb, tvb_offset+1);
tokenlen = tvb_next_offset - tvb_offset;
if (tokenlen+1 <= 0) {
expert_add_info_format(pinfo, sub_ti, &ei_megaco_parse_error, "Parse error: Invalid token length (%d)", tokenlen+1);
return tvb_captured_length(tvb);
}
tempchar = tvb_get_guint8(tvb, tvb_offset);
if ( (tempchar >= 'a')&& (tempchar <= 'z'))
tempchar = tempchar - 0x20;
term = wmem_new0(wmem_packet_scope(), gcp_term_t);
wild_term = GCP_WILDCARD_NONE;
term->type = GCP_TERM_TYPE_UNKNOWN;
switch ( tempchar ){
case 'E':
if ((tokenlen+1 > (int) sizeof(TermID))) {
expert_add_info_format(pinfo, sub_ti, &ei_megaco_parse_error, "Parse error: Invalid TermID length (%d)", tokenlen+1);
return tvb_captured_length(tvb);
}
tvb_get_nstringz0(tvb,tvb_offset,tokenlen+1,TermID);
TermID[0] = 'e';
term->len = tokenlen;
term->str = (const gchar*)(term->buffer = TermID);
gcp_cmd_add_term(msg, trx, cmd, term, wild_term, pinfo, keep_persistent_data);
/*** TERM ***/
proto_tree_add_string(megaco_tree_command_line, hf_megaco_termid, tvb,
tvb_offset, tokenlen, TermID);
break;
case '*':
wild_term = GCP_WILDCARD_ALL;
term->len = 1;
term->buffer = (const guint8*)(term->str = "*");
gcp_cmd_add_term(msg, trx, cmd, term, wild_term, pinfo, keep_persistent_data);
proto_tree_add_string(megaco_tree_command_line, hf_megaco_termid, tvb,
tvb_offset, tokenlen,
"WildCard all");
col_append_str(pinfo->cinfo, COL_INFO, "=*");
break;
case '$':
wild_term = GCP_WILDCARD_CHOOSE;
term->len = 1;
term->buffer = (term->str = "$");
gcp_cmd_add_term(msg, trx, cmd, term, wild_term, pinfo, keep_persistent_data);
proto_tree_add_string(megaco_tree_command_line, hf_megaco_termid, tvb,
tvb_offset, tokenlen,
"WildCard any");
col_append_str(pinfo->cinfo, COL_INFO, "=$");
break;
case 'O':
break;
default:
/*** TERM ***/
switch (megaco_command) {
case MEGACO_CMD_PRIORITY:
proto_tree_add_string(megaco_tree_command_line, hf_megaco_priority, tvb,
tvb_offset, tokenlen,
tvb_format_text(pinfo->pool, tvb, tvb_offset,
tokenlen));
break;
default:
proto_tree_add_string(megaco_tree_command_line, hf_megaco_termid, tvb,
tvb_offset, tokenlen,
tvb_format_text(pinfo->pool, tvb, tvb_offset,
tokenlen));
term->len = tokenlen;
term->buffer = (const guint8*)(term->str = tvb_format_text(pinfo->pool, tvb, tvb_offset, tokenlen));
gcp_cmd_add_term(msg, trx, cmd, term, wild_term, pinfo, keep_persistent_data);
break;
}
col_append_fstr(pinfo->cinfo, COL_INFO, "=%s",tvb_format_text(pinfo->pool, tvb, tvb_offset,tokenlen));
break;
}
}
/* Dissect the Descriptors */
if ( LBRKT_counter != 0 && tvb_current_offset != tvb_command_end_offset){
tvb_descriptors_start_offset = tvb_find_guint8(tvb, tvb_command_start_offset,
tvb_transaction_end_offset, '{');
tvb_descriptors_end_offset = tvb_descriptors_start_offset;
if ( tvb_descriptors_end_offset > tvb_transaction_end_offset )
tvb_descriptors_end_offset = tvb_transaction_end_offset;
while ( LBRKT_counter > 0 ){
tvb_descriptors_end_offset = tvb_find_guint8(tvb, tvb_descriptors_end_offset+1,
tvb_transaction_end_offset, '}');
LBRKT_counter--;
}
tempchar = tvb_get_guint8(tvb, tvb_command_start_offset);
if ( tempchar == 'E'|| tempchar == 'e'){
dissect_megaco_descriptors(tvb, megaco_tree_command_line, pinfo, tvb_command_start_offset-1,tvb_descriptors_end_offset, tree, ctx_id);
}
else {
dissect_megaco_descriptors(tvb, megaco_tree_command_line, pinfo, tvb_descriptors_start_offset,tvb_descriptors_end_offset, tree, ctx_id);
}
}
RBRKT_counter = 0;
LBRKT_counter = 0;
tvb_command_start_offset = megaco_tvb_skip_wsp(tvb, tvb_command_end_offset +1);
tvb_LBRKT = tvb_command_start_offset;
tvb_RBRKT = tvb_command_start_offset;
}
} while ( tvb_command_end_offset < tvb_transaction_end_offset );
if (keep_persistent_data) {
gcp_msg_to_str(msg,pinfo->pool,keep_persistent_data);
gcp_analyze_msg(megaco_tree, pinfo, tvb, msg, &megaco_ctx_ids, &ei_megaco_errored_command);
}
tvb_next_offset = tvb_transaction_end_offset;
}
while( tvb_transaction_end_offset > 0 && tvb_transaction_end_offset < tvb_len - 2);
if(global_megaco_raw_text){
tvb_raw_text_add(tvb, megaco_tree);
}
return tvb_captured_length(tvb);
}
#define MEGACO_MODEM_TOKEN 1
#define MEGACO_MUX_TOKEN 2
#define MEGACO_MEDIA_TOKEN 3
#define MEGACO_SIGNALS_TOKEN 4
#define MEGACO_SERVICES_TOKEN 5
#define MEGACO_STATS_TOKEN 6
#define MEGACO_ERROR_TOKEN 7
#define MEGACO_EVENTS_TOKEN 8
#define MEGACO_AUDIT_TOKEN 9
#define MEGACO_DIGITMAP_TOKEN 10
#define MEGACO_OE_TOKEN 11
#define MEGACO_TOPOLOGY_TOKEN 12
#define MEGACO_PACKAGES_TOKEN 13
static const megaco_tokens_t megaco_descriptors_names[] = {
{ "Unknown-token", NULL }, /* 0 Pad so that the real headers start at index 1 */
{ "Modem", "MD" }, /* 1 */
{ "Mux", "MX" }, /* 2 */
{ "Media", "M" }, /* 3 */
{ "Signals", "SG" }, /* 4 */
{ "Services", "SV" }, /* 5 */
{ "Statistics", "SA" }, /* 6 */
{ "Error", "ER" }, /* 7 */
{ "Events", "E" }, /* 8 */
{ "Audit", "AT" }, /* 9 */
{ "DigitMap", "DM" }, /* 10 */
{ "ObservedEvents", "OE" }, /* 11 */
{ "Topology", "TP" }, /* 12 */
{ "Packages", "PG" }, /* 13 */
};
/* Returns index of megaco_tokens_t */
/* note - also called by dissect_megaco_auditdescriptor */
static gint find_megaco_descriptors_names(tvbuff_t *tvb, int offset, guint header_len)
{
guint i;
for (i = 1; i < array_length(megaco_descriptors_names); i++) {
if (header_len == strlen(megaco_descriptors_names[i].name) &&
tvb_strncaseeql(tvb, offset, megaco_descriptors_names[i].name, header_len) == 0)
return i;
if (megaco_descriptors_names[i].compact_name != NULL &&
header_len == strlen(megaco_descriptors_names[i].compact_name) &&
tvb_strncaseeql(tvb, offset, megaco_descriptors_names[i].compact_name, header_len) == 0)
return i;
}
return -1;
}
static void
dissect_megaco_modemdescriptor(tvbuff_t *tvb, proto_tree *megaco_tree_command_line, gint tvb_RBRKT, gint tvb_previous_offset)
{
gint tokenlen;
tokenlen = (tvb_RBRKT+1) - tvb_previous_offset;
proto_tree_add_string(megaco_tree_command_line, hf_megaco_modem_descriptor, tvb,
tvb_previous_offset, tokenlen,
tvb_format_text(wmem_packet_scope(), tvb, tvb_previous_offset,
tokenlen));
}
static void
dissect_megaco_multiplexdescriptor(tvbuff_t *tvb, proto_tree *megaco_tree_command_line, gint tvb_RBRKT, gint tvb_previous_offset)
{
gint tokenlen;
tokenlen = (tvb_RBRKT+1) - tvb_previous_offset;
proto_tree_add_string(megaco_tree_command_line, hf_megaco_multiplex_descriptor, tvb,
tvb_previous_offset, tokenlen,
tvb_format_text(wmem_packet_scope(), tvb, tvb_previous_offset,
tokenlen));
}
/* mediaDescriptor = MediaToken LBRKT mediaParm *(COMMA mediaParm) RBRKT
* MediaToken = ("Media" / "M")
*
* mediaParm = (streamParm / streamDescriptor /terminationStateDescriptor)
*
* ; at-most one terminationStateDescriptor
* ; and either streamParm(s) or streamDescriptor(s) but not both
* streamParm = ( localDescriptor / remoteDescriptor /localControlDescriptor )
* localDescriptor = LocalToken LBRKT octetString RBRKT
* LocalToken = ("Local" / "L")
* octetString = *(nonEscapeChar)
* nonEscapeChar = ( "\}" / %x01-7C / %x7E-FF )
* remoteDescriptor = RemoteToken LBRKT octetString RBRKT
* RemoteToken = ("Remote" / "R")
* localControlDescriptor = LocalControlToken LBRKT localParm*(COMMA localParm) RBRKT
* LocalControlToken = ("LocalControl" / "O")
* localParm = ( streamMode / propertyParm / reservedValueMode
* streamDescriptor = StreamToken EQUAL StreamID LBRKT streamParm*(COMMA streamParm) RBRKT
* StreamToken = ("Stream" / "ST")
* terminationStateDescriptor = TerminationStateToken LBRKTterminationStateParm
* *( COMMA terminationStateParm ) RBRKT
* TerminationStateToken = ("TerminationState" / "TS")
* terminationStateParm =(propertyParm / serviceStates / eventBufferControl )
*/
#define MEGACO_LOCAL_TOKEN 1
#define MEGACO_REMOTE_TOKEN 2
#define MEGACO_LOCAL_CONTROL_TOKEN 3
#define MEGACO_STREAM_TOKEN 4
#define MEGACO_TERMINATION_STATE_DESC 5
static const megaco_tokens_t megaco_mediaParm_names[] = {
{ "Unknown-token", NULL }, /* 0 Pad so that the real headers start at index 1 */
{ "Local", "L" }, /* 1 */
{ "Remote", "R" }, /* 2 */
{ "LocalControl", "O" }, /* 3 */
{ "Stream", "ST" }, /* 4 */
{ "TerminationState", "TS" }, /* 5 */
};
/* Returns index of megaco_tokens_t */
static gint find_megaco_mediaParm_names(tvbuff_t *tvb, int offset, guint header_len)
{
guint i;
for (i = 1; i < array_length(megaco_mediaParm_names); i++) {
if (header_len == strlen(megaco_mediaParm_names[i].name) &&
tvb_strncaseeql(tvb, offset, megaco_mediaParm_names[i].name, header_len) == 0)
return i;
if (megaco_mediaParm_names[i].compact_name != NULL &&
header_len == strlen(megaco_mediaParm_names[i].compact_name) &&
tvb_strncaseeql(tvb, offset, megaco_mediaParm_names[i].compact_name, header_len) == 0)
return i;
}
return -1;
}
static void
dissect_megaco_mediadescriptor(tvbuff_t *tvb, proto_tree *megaco_tree_command_line,packet_info *pinfo, gint tvb_last_RBRKT,
gint tvb_previous_offset, gint start_offset, proto_tree *top_tree, guint32 context)
{
gint tokenlen, tvb_LBRKT, tvb_RBRKT;
gint tvb_next_offset, tvb_current_offset, tvb_offset, equal_offset, save_offset;
gint mediaParm;
guint streamId;
proto_tree *megaco_mediadescriptor_tree;
proto_item *megaco_mediadescriptor_ti, *ti;
megaco_mediadescriptor_ti = proto_tree_add_item(megaco_tree_command_line, hf_megaco_media_descriptor, tvb, start_offset, 1, ENC_NA);
megaco_mediadescriptor_tree = proto_item_add_subtree(megaco_mediadescriptor_ti, ett_megaco_mediadescriptor);
while ( tvb_previous_offset < tvb_last_RBRKT){
/* Start of token */
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_previous_offset);
/* Find token length */
for (tvb_next_offset=tvb_current_offset; tvb_next_offset < tvb_last_RBRKT; tvb_next_offset++){
if (!g_ascii_isalpha(tvb_get_guint8(tvb, tvb_next_offset ))){
break;
}
}
tokenlen = tvb_next_offset - tvb_current_offset;
mediaParm = find_megaco_mediaParm_names(tvb, tvb_current_offset, tokenlen);
tvb_LBRKT = tvb_find_guint8(tvb, tvb_next_offset , tvb_last_RBRKT, '{');
tvb_next_offset = tvb_find_guint8(tvb, tvb_current_offset+1 , tvb_last_RBRKT, '}');
tvb_RBRKT = tvb_next_offset;
switch ( mediaParm ){
case MEGACO_LOCAL_TOKEN:
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_LBRKT+1);
dissect_megaco_LocalRemotedescriptor(tvb, megaco_mediadescriptor_tree, pinfo,
tvb_RBRKT, tvb_current_offset, context, TRUE);
tvb_current_offset = tvb_RBRKT;
break;
case MEGACO_REMOTE_TOKEN:
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_LBRKT+1);
dissect_megaco_LocalRemotedescriptor(tvb, megaco_mediadescriptor_tree, pinfo,
tvb_RBRKT, tvb_current_offset, context, FALSE);
tvb_current_offset = tvb_RBRKT;
break;
case MEGACO_LOCAL_CONTROL_TOKEN:
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_LBRKT+1);
dissect_megaco_LocalControldescriptor(tvb, megaco_mediadescriptor_tree, pinfo,
tvb_RBRKT, tvb_current_offset, top_tree);
tvb_current_offset = tvb_RBRKT;
break;
case MEGACO_STREAM_TOKEN:
save_offset = tvb_current_offset;
equal_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_last_RBRKT, '=');
tvb_current_offset = megaco_tvb_skip_wsp(tvb, equal_offset+1);
tvb_offset = megaco_tvb_skip_wsp_return(tvb, tvb_LBRKT-1);
tokenlen = tvb_offset - tvb_current_offset;
streamId = (guint)strtoul(tvb_format_text(pinfo->pool, tvb, tvb_current_offset,tokenlen),NULL,10);
ti = proto_tree_add_uint(megaco_mediadescriptor_tree, hf_megaco_streamid, tvb,
save_offset, 1, streamId);
proto_item_set_len(ti, tvb_offset-save_offset+tokenlen);
tvb_previous_offset = tvb_LBRKT+1;
continue;
case MEGACO_TERMINATION_STATE_DESC:
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_LBRKT+1);
dissect_megaco_TerminationStatedescriptor(tvb, megaco_mediadescriptor_tree,
tvb_RBRKT, tvb_current_offset);
tvb_current_offset = tvb_RBRKT;
break;
default:
break;
};
/* more parameters ? */
tvb_next_offset = tvb_find_guint8(tvb, tvb_current_offset+1 , tvb_last_RBRKT, ',');
if (tvb_next_offset > tvb_last_RBRKT) tvb_next_offset = tvb_last_RBRKT;
if ( tvb_next_offset != -1 ){
/* (raw formatting removed)
tokenlen = tvb_next_offset - tvb_RBRKT+1;
proto_tree_add_format_text(megaco_mediadescriptor_tree, tvb, tvb_RBRKT, tokenlen); */
tvb_previous_offset = tvb_next_offset+1;
} else{
/* Add the trailing '}' (raw formatting removed) */
/* proto_tree_add_format_text(megaco_mediadescriptor_tree, tvb, tvb_RBRKT, 1); */
tvb_previous_offset = tvb_last_RBRKT;
}
} /* End while */
proto_item_set_end(megaco_mediadescriptor_ti, tvb, tvb_previous_offset);
}
static void
dissect_megaco_h245(tvbuff_t *tvb, packet_info *pinfo, proto_tree *megaco_tree, gint offset, gint len, proto_tree *top_tree)
{
/*proto_item *item;*/
/*proto_tree *tree;*/
gchar *msg = tvb_format_text(pinfo->pool, tvb, offset, len);
/*item= */proto_tree_add_item(megaco_tree, hf_megaco_h245, tvb, offset, len, ENC_NA);
/*tree = proto_item_add_subtree(item, ett_megaco_h245); */
/* arbitrary maximum length */
if(len<20480){
int i;
tvbuff_t *h245_tvb;
guint8 *buf = (guint8 *)wmem_alloc(pinfo->pool, 10240);
/* first, skip to where the encoded pdu starts, this is
the first hex digit after the '=' char.
*/
while(1){
if((*msg==0)||(*msg=='\n')){
return;
}
if(*msg=='='){
msg++;
break;
}
msg++;
}
while(1){
if((*msg==0)||(*msg=='\n')){
return;
}
if( ((*msg>='0')&&(*msg<='9'))
|| ((*msg>='a')&&(*msg<='f'))
|| ((*msg>='A')&&(*msg<='F'))){
break;
}
msg++;
}
i=0;
while( ((*msg>='0')&&(*msg<='9'))
||((*msg>='a')&&(*msg<='f'))
||((*msg>='A')&&(*msg<='F')) ){
int val;
if((*msg>='0')&&(*msg<='9')){
val=(*msg)-'0';
} else if((*msg>='a')&&(*msg<='f')){
val=(*msg)-'a'+10;
} else if((*msg>='A')&&(*msg<='F')){
val=(*msg)-'A'+10;
} else {
return;
}
val<<=4;
msg++;
if((*msg>='0')&&(*msg<='9')){
val|=(*msg)-'0';
} else if((*msg>='a')&&(*msg<='f')){
val|=(*msg)-'a'+10;
} else if((*msg>='A')&&(*msg<='F')){
val|=(*msg)-'A'+10;
} else {
return;
}
msg++;
buf[i]=(guint8)val;
i++;
}
if(i==0){
return;
}
h245_tvb = tvb_new_child_real_data(tvb, buf,i,i);
add_new_data_source(pinfo, h245_tvb, "H.245 over MEGACO");
/* should go through a handle, however, the two h245 entry
points are different, one is over tpkt and the other is raw
*/
call_dissector(h245_handle, h245_tvb, pinfo, top_tree);
/* dissect_h245_MultimediaSystemControlMessage(h245_tvb, pinfo, tree);*/
}
}
static void
dissect_megaco_h324_h223caprn(tvbuff_t *tvb, packet_info *pinfo, proto_tree *megaco_tree, gint offset _U_, gint len, gchar *msg)
{
asn1_ctx_t actx;
/* arbitrary maximum length */
if(len<20480){
int i;
tvbuff_t *h245_tvb;
guint8 *buf = (guint8 *)wmem_alloc(pinfo->pool, 10240);
/* first, skip to where the encoded pdu starts, this is
the first hex digit after the '=' char.
*/
while(1){
if((*msg==0)||(*msg=='\n')){
return;
}
if(*msg=='='){
msg++;
break;
}
msg++;
}
while(1){
if((*msg==0)||(*msg=='\n')){
return;
}
if( ((*msg>='0')&&(*msg<='9'))
|| ((*msg>='a')&&(*msg<='f'))
|| ((*msg>='A')&&(*msg<='F'))){
break;
}
msg++;
}
i=0;
while( ((*msg>='0')&&(*msg<='9'))
||((*msg>='a')&&(*msg<='f'))
||((*msg>='A')&&(*msg<='F')) ){
int val;
if((*msg>='0')&&(*msg<='9')){
val=(*msg)-'0';
} else if((*msg>='a')&&(*msg<='f')){
val=(*msg)-'a'+10;
} else if((*msg>='A')&&(*msg<='F')){
val=(*msg)-'A'+10;
} else {
return;
}
val<<=4;
msg++;
if((*msg>='0')&&(*msg<='9')){
val|=(*msg)-'0';
} else if((*msg>='a')&&(*msg<='f')){
val|=(*msg)-'a'+10;
} else if((*msg>='A')&&(*msg<='F')){
val|=(*msg)-'A'+10;
} else {
return;
}
msg++;
buf[i]=(guint8)val;
i++;
}
if(i==0){
return;
}
h245_tvb = tvb_new_child_real_data(tvb, buf,i,i);
add_new_data_source(pinfo, h245_tvb, "H.245 over MEGACO");
/* should go through a handle, however, the two h245 entry
points are different, one is over tpkt and the other is raw
*/
asn1_ctx_init(&actx, ASN1_ENC_PER, TRUE, pinfo);
dissect_h245_H223Capability(h245_tvb, 0, &actx, megaco_tree, hf_megaco_h223Capability);
}
}
static void
dissect_megaco_eventsdescriptor(tvbuff_t *tvb, packet_info *pinfo, proto_tree *megaco_tree_command_line, gint tvb_RBRKT, gint tvb_previous_offset, proto_tree *top_tree)
{
gint tokenlen, tvb_current_offset, tvb_next_offset, tvb_help_offset;
gint tvb_events_end_offset, tvb_LBRKT;
proto_tree *megaco_eventsdescriptor_tree, *megaco_requestedevent_tree;
proto_item *megaco_eventsdescriptor_ti, *megaco_requestedevent_ti, *ti;
gint requested_event_start_offset = 0,
requested_event_end_offset = 0;
tokenlen = (tvb_RBRKT+1) - tvb_previous_offset;
megaco_eventsdescriptor_ti = proto_tree_add_item(megaco_tree_command_line,hf_megaco_events_descriptor,tvb,tvb_previous_offset, tokenlen, ENC_NA);
megaco_eventsdescriptor_tree = proto_item_add_subtree(megaco_eventsdescriptor_ti, ett_megaco_eventsdescriptor);
tvb_current_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_RBRKT, '=');
tvb_next_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_RBRKT, '{');
if ( tvb_current_offset < tvb_RBRKT && tvb_current_offset != -1 ){
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_current_offset +1);
tvb_help_offset = megaco_tvb_skip_wsp_return(tvb, tvb_next_offset-1);
tokenlen = tvb_help_offset - tvb_current_offset;
ti = proto_tree_add_uint(megaco_eventsdescriptor_tree, hf_megaco_requestid, tvb,
tvb_current_offset, 1,
(guint32) strtoul(tvb_format_text(pinfo->pool, tvb, tvb_current_offset, tokenlen), NULL, 10));
proto_item_set_len(ti, tokenlen);
tvb_events_end_offset = tvb_RBRKT;
tvb_RBRKT = tvb_next_offset+1;
tvb_LBRKT = tvb_next_offset+1;
tvb_previous_offset = megaco_tvb_skip_wsp(tvb, tvb_next_offset+1);
do {
tvb_RBRKT = tvb_find_guint8(tvb, tvb_RBRKT+1,
tvb_events_end_offset, '}');
tvb_LBRKT = tvb_find_guint8(tvb, tvb_LBRKT,
tvb_events_end_offset, '{');
tvb_current_offset = tvb_find_guint8(tvb, tvb_previous_offset,
tvb_events_end_offset, ',');
if (tvb_current_offset == -1 || tvb_current_offset > tvb_events_end_offset){
tvb_current_offset = tvb_events_end_offset;
}
/* Descriptor includes no parameters */
if ( tvb_LBRKT > tvb_current_offset || tvb_LBRKT == -1 ){
tvb_RBRKT = megaco_tvb_skip_wsp_return(tvb, tvb_current_offset-1)-1;
}
/* Descriptor includes Parameters */
if ( (tvb_current_offset > tvb_LBRKT && tvb_LBRKT != -1)){
while ( tvb_LBRKT != -1 && tvb_RBRKT > tvb_LBRKT ){
tvb_LBRKT = tvb_find_guint8(tvb, tvb_LBRKT+1,
tvb_events_end_offset, '{');
if ( tvb_LBRKT < tvb_RBRKT && tvb_LBRKT != -1)
tvb_RBRKT = tvb_find_guint8(tvb, tvb_RBRKT+1,
tvb_events_end_offset, '}');
}
}
tvb_help_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_events_end_offset, '{');
/* if there are eventparameter */
if ( tvb_help_offset < tvb_RBRKT && tvb_help_offset != -1 ){
requested_event_start_offset = tvb_help_offset;
requested_event_end_offset = tvb_RBRKT;
tvb_help_offset = megaco_tvb_skip_wsp_return(tvb, tvb_help_offset-1);
tokenlen = tvb_help_offset - tvb_previous_offset;
}
/* no parameters */
else {
tokenlen = tvb_RBRKT+1 - tvb_previous_offset;
}
megaco_requestedevent_ti = proto_tree_add_item(megaco_eventsdescriptor_tree,hf_megaco_pkgdname,tvb,tvb_previous_offset,tokenlen, ENC_UTF_8);
megaco_requestedevent_tree = proto_item_add_subtree(megaco_requestedevent_ti, ett_megaco_requestedevent);
if ( tvb_help_offset < tvb_RBRKT && tvb_help_offset != -1 ){
requested_event_start_offset = megaco_tvb_skip_wsp(tvb, requested_event_start_offset +1);
requested_event_end_offset = megaco_tvb_skip_wsp_return(tvb, requested_event_end_offset-1);
if (!tvb_strncaseeql(tvb, requested_event_start_offset, "dm", 2)) {
dissect_megaco_digitmapdescriptor(tvb, megaco_requestedevent_tree, requested_event_end_offset, requested_event_start_offset);
}
else{
tokenlen = requested_event_end_offset - requested_event_start_offset;
if(!tvb_strneql(tvb, requested_event_start_offset, "h245", 4)){
dissect_megaco_h245(tvb, pinfo, megaco_requestedevent_tree, requested_event_start_offset, tokenlen, top_tree);
} else {
proto_tree_add_format_text(megaco_requestedevent_tree, tvb, requested_event_start_offset, tokenlen);
}
}
}
tvb_previous_offset = tvb_current_offset;
tvb_current_offset = tvb_find_guint8(tvb, tvb_RBRKT,
tvb_events_end_offset, ',');
if (tvb_current_offset == -1 || tvb_current_offset > tvb_events_end_offset || tvb_current_offset < tvb_previous_offset ) {
tvb_current_offset = tvb_events_end_offset;
}
tvb_previous_offset = megaco_tvb_skip_wsp(tvb, tvb_current_offset+1);
tvb_LBRKT = tvb_previous_offset;
tvb_RBRKT = tvb_previous_offset;
} while ( tvb_current_offset < tvb_events_end_offset );
}
}
static void
dissect_megaco_signaldescriptor(tvbuff_t *tvb, packet_info *pinfo, proto_tree *megaco_tree_command_line, gint tvb_RBRKT, gint tvb_previous_offset, proto_tree *top_tree)
{
gint tokenlen, pkg_tokenlen, tvb_current_offset, tvb_next_offset, tvb_help_offset;
gint tvb_signals_end_offset, tvb_signals_start_offset, tvb_LBRKT;
proto_tree *megaco_signalsdescriptor_tree, *megaco_requestedsignal_tree;
proto_item *megaco_signalsdescriptor_ti, *megaco_requestedsignal_ti;
gint requested_signal_start_offset = 0,
requested_signal_end_offset = 0;
tvb_signals_end_offset = tvb_RBRKT;
tvb_signals_start_offset = tvb_previous_offset;
if(g_ascii_toupper(tvb_get_guint8(tvb, tvb_previous_offset+1))=='G')
tokenlen = 2; /* token is compact text (SG) */
else
tokenlen = 7; /* token must be verbose text (Signals) */
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_previous_offset+tokenlen);
if(tvb_get_guint8(tvb, tvb_current_offset)!='{') { /* {} has been omitted */
megaco_signalsdescriptor_ti = proto_tree_add_item(megaco_tree_command_line, hf_megaco_signal_descriptor, tvb, tvb_signals_start_offset, tokenlen, ENC_NA);
expert_add_info(pinfo, megaco_signalsdescriptor_ti, &ei_megaco_signal_descriptor);
col_append_str(pinfo->cinfo, COL_INFO, " (Signal:none)"); /* then say so */
return; /* and return */
}
tvb_LBRKT = tvb_find_guint8(tvb, tvb_previous_offset, tvb_signals_end_offset, '{');
tokenlen = (tvb_LBRKT+1) - tvb_signals_start_offset;
megaco_signalsdescriptor_ti = proto_tree_add_item(megaco_tree_command_line,hf_megaco_signal_descriptor,tvb,tvb_previous_offset,tokenlen, ENC_NA);
megaco_signalsdescriptor_tree = proto_item_add_subtree(megaco_signalsdescriptor_ti, ett_megaco_signalsdescriptor);
tvb_current_offset = tvb_LBRKT;
tvb_next_offset = megaco_tvb_skip_wsp(tvb, tvb_current_offset+1);
col_append_fstr(pinfo->cinfo, COL_INFO, " (Signal:%s)",tvb_format_text(pinfo->pool, tvb, tvb_current_offset,tokenlen-tvb_current_offset+tvb_previous_offset));
if ( tvb_current_offset < tvb_signals_end_offset && tvb_current_offset != -1 && tvb_next_offset != tvb_signals_end_offset){
tvb_RBRKT = tvb_next_offset+1;
tvb_LBRKT = tvb_next_offset+1;
tvb_previous_offset = tvb_next_offset;
do {
tvb_RBRKT = tvb_find_guint8(tvb, tvb_RBRKT+1,
tvb_signals_end_offset, '}');
tvb_LBRKT = tvb_find_guint8(tvb, tvb_LBRKT,
tvb_signals_end_offset, '{');
tvb_current_offset = tvb_find_guint8(tvb, tvb_previous_offset,
tvb_signals_end_offset, ',');
if (tvb_current_offset == -1 || tvb_current_offset > tvb_signals_end_offset){
tvb_current_offset = tvb_signals_end_offset;
}
/* Descriptor includes no parameters */
if ( tvb_LBRKT > tvb_current_offset || tvb_LBRKT == -1 ){
tvb_RBRKT = megaco_tvb_skip_wsp_return(tvb, tvb_current_offset-1)-1;
}
/* Descriptor includes Parameters */
if ( (tvb_current_offset > tvb_LBRKT && tvb_LBRKT != -1)){
while ( tvb_LBRKT != -1 && tvb_RBRKT > tvb_LBRKT ){
tvb_LBRKT = tvb_find_guint8(tvb, tvb_LBRKT+1,
tvb_signals_end_offset, '{');
if ( tvb_LBRKT < tvb_RBRKT && tvb_LBRKT != -1)
tvb_RBRKT = tvb_find_guint8(tvb, tvb_RBRKT+1,
tvb_signals_end_offset, '}');
}
}
tvb_help_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_signals_end_offset, '{');
/* if there are signalparameter */
if ( tvb_help_offset < tvb_RBRKT && tvb_help_offset != -1 ){
requested_signal_start_offset = tvb_help_offset;
requested_signal_end_offset = tvb_RBRKT;
tvb_help_offset = megaco_tvb_skip_wsp_return(tvb, tvb_help_offset-1);
pkg_tokenlen = tvb_help_offset - tvb_previous_offset;
}
/* no parameters */
else {
pkg_tokenlen = tvb_RBRKT+1 - tvb_previous_offset;
}
megaco_requestedsignal_ti = proto_tree_add_item(megaco_signalsdescriptor_tree,hf_megaco_pkgdname,tvb,tvb_previous_offset,pkg_tokenlen, ENC_UTF_8);
megaco_requestedsignal_tree = proto_item_add_subtree(megaco_requestedsignal_ti, ett_megaco_requestedsignal);
if ( tvb_help_offset < tvb_RBRKT && tvb_help_offset != -1 ){
requested_signal_start_offset = megaco_tvb_skip_wsp(tvb, requested_signal_start_offset +1);
requested_signal_end_offset = megaco_tvb_skip_wsp_return(tvb, requested_signal_end_offset-1);
tokenlen = requested_signal_end_offset - requested_signal_start_offset;
if(!tvb_strneql(tvb, requested_signal_start_offset, "h245", 4)){
dissect_megaco_h245(tvb, pinfo, megaco_requestedsignal_tree, requested_signal_start_offset, tokenlen, top_tree);
} else {
proto_tree_add_format_text( megaco_requestedsignal_tree, tvb, requested_signal_start_offset, tokenlen);
}
/* Print the trailing '}' (raw formatting removed) */
/* proto_tree_add_format_text( megaco_requestedsignal_tree, tvb, tvb_RBRKT, 1); */
}
tvb_current_offset = tvb_find_guint8(tvb, tvb_RBRKT,
tvb_signals_end_offset, ',');
if (tvb_current_offset == -1 || tvb_current_offset > tvb_signals_end_offset || tvb_current_offset < tvb_previous_offset){
tvb_current_offset = tvb_signals_end_offset;
}
tvb_previous_offset = megaco_tvb_skip_wsp(tvb, tvb_current_offset+1);
tvb_LBRKT = tvb_previous_offset;
tvb_RBRKT = tvb_previous_offset;
/* Print the trailing '}' (raw formatting removed) */
/* proto_tree_add_format_text(megaco_tree_command_line, tvb, tvb_signals_end_offset, 1); */
} while ( tvb_current_offset < tvb_signals_end_offset );
}else{
/* signals{} (raw formatting removed)
proto_tree_add_format_text(megaco_tree_command_line, tvb, tvb_signals_end_offset, 1); */
}
}
/*
auditDescriptor = AuditToken LBRKT [ auditItem *(COMMA auditItem) ] RBRKT
auditItem = ( MuxToken / ModemToken / MediaToken /
SignalsToken / EventBufferToken /
DigitMapToken / StatsToken / EventsToken /
ObservedEventsToken / PackagesToken ) */
static void
dissect_megaco_auditdescriptor(tvbuff_t *tvb, proto_tree *megaco_tree, packet_info *pinfo _U_, gint tvb_stop, gint tvb_offset)
{
gint tokenlen, tvb_end, tvb_next, token_index;
proto_tree *megaco_auditdescriptor_tree, *megaco_auditdescriptor_ti;
tvb_next = tvb_find_guint8(tvb, tvb_offset, tvb_stop, '{'); /* find opening LBRKT - is this already checked by caller?*/
if( tvb_next == -1 ) /* complain and give up if not there */
{
expert_add_info(pinfo, megaco_tree, &ei_megaco_audit_descriptor);
return;
}
tokenlen = (tvb_stop + 1) - tvb_offset;
megaco_auditdescriptor_ti = proto_tree_add_item( megaco_tree, hf_megaco_audit_descriptor, tvb, tvb_offset, tokenlen, ENC_NA);
megaco_auditdescriptor_tree = proto_item_add_subtree( megaco_auditdescriptor_ti, ett_megaco_auditdescriptor );
tvb_offset = tvb_next;
while( tvb_offset < tvb_stop )
{
tvb_offset = megaco_tvb_skip_wsp(tvb, tvb_offset+1); /* find start of an auditItem */
if( tvb_get_guint8(tvb, tvb_offset) != '}' ) /* got something */
{
tvb_next = tvb_find_guint8(tvb, tvb_offset, tvb_stop, ','); /* end of an auditItem */
if (tvb_next == -1) /* last item doesn't have a comma */
tvb_next = tvb_stop;
tvb_end = megaco_tvb_skip_wsp_return(tvb, tvb_next-1); /* trim any trailing whitespace */
tokenlen = tvb_end - tvb_offset; /* get length of token */
token_index = find_megaco_descriptors_names(tvb, tvb_offset, tokenlen); /* lookup the token */
if( token_index == -1 ) /* if not found then 0 => Unknown */
token_index = 0;
proto_tree_add_string(megaco_auditdescriptor_tree, hf_megaco_audititem, tvb,
tvb_offset, tokenlen, megaco_descriptors_names[token_index].name); /* and display the long form */
tvb_offset = tvb_next; /* advance pointer */
}
}
}
/*
* serviceChangeDescriptor = ServicesToken LBRKT serviceChangeParm
* *(COMMA serviceChangeParm) RBRKT
*
* ServicesToken = ("Services" / "SV")
*
* serviceChangeParm = (serviceChangeMethod / serviceChangeReason /
* serviceChangeDelay / serviceChangeAddress /
* serviceChangeProfile / extension / TimeStamp /
* serviceChangeMgcId / serviceChangeVersion )
*
*/
#define MEGACO_REASON_TOKEN 1
#define MEGACO_DELAY_TOKEN 2
#define MEGACO_SC_ADDR_TOKEN 3
#define MEGACO_MGC_ID_TOKEN 4
#define MEGACO_PROFILE_TOKEN 5
#define MEGACO_VERSION_TOKEN 6
#define MEGACO_METHOD_TOKEN 7
static const megaco_tokens_t megaco_serviceChangeParm_names[] = {
{ "Unknown-token", NULL }, /* 0 Pad so that the real headers start at index 1 */
/* streamMode */
{ "Reason", "RE" }, /* 1 ReasonToken*/
{ "Delay", "DL" }, /* 2 DelayToken */
{ "ServiceChangeAddress", "AD" }, /* 3 ServiceChangeAddressToken */
{ "MgcIdToTry", "MG" }, /* 4 MgcIdToken */
{ "Profile", "PF" }, /* 5 ProfileToken */
{ "Version", "V" }, /* 6 VersionToken */
{ "Method", "MT" }, /* 7 MethodToken */
};
/* Returns index of megaco_tokens_t */
static gint find_megaco_megaco_serviceChangeParm_names(tvbuff_t *tvb, int offset, guint header_len)
{
guint i;
for (i = 1; i < array_length(megaco_serviceChangeParm_names); i++) {
if (header_len == strlen(megaco_serviceChangeParm_names[i].name) &&
tvb_strncaseeql(tvb, offset, megaco_serviceChangeParm_names[i].name, header_len) == 0)
return i;
if (megaco_serviceChangeParm_names[i].compact_name != NULL &&
header_len == strlen(megaco_serviceChangeParm_names[i].compact_name) &&
tvb_strncaseeql(tvb, offset, megaco_serviceChangeParm_names[i].compact_name, header_len) == 0)
return i;
}
return -1;
}
/*
* ServiceChangeReasons References
* -------------------- ----------
*/
static const value_string MEGACO_ServiceChangeReasons_vals[] = {
{900, "Service Restored"},
{901, "Cold Boot"},
{902, "Warm Boot"},
{903, "MGC Directed Change"},
{904, "Termination malfunctioning"},
{905, "Termination taken out of service"},
{906, "Loss of lower layer connectivity (e.g. downstream sync)"},
{907, "Transmission Failure"},
{908, "MG Impending Failure"},
{909, "MGC Impending Failure"},
{910, "Media Capability Failure"},
{911, "Modem Capability Failure"},
{912, "Mux Capability Failure"},
{913, "Signal Capability Failure"},
{914, "Event Capability Failure"},
{915, "State Loss"},
{916, "Packages Change"},
{917, "Capabilities Change"},
{918, "Cancel Graceful"},
{919, "Warm Failover"},
{920, "Cold Failover"},
{ 0, NULL }
};
static void
dissect_megaco_servicechangedescriptor(tvbuff_t *tvb, packet_info* pinfo, proto_tree *megaco_tree, gint tvb_RBRKT,
gint tvb_previous_offset)
{
gint tokenlen, tvb_LBRKT, tvb_offset;
gint token_index;
gint tvb_current_offset;
gboolean more_params = TRUE;
proto_item* item;
gint reason;
gboolean reason_valid;
guint8 ServiceChangeReason_str[4];
tvb_LBRKT = tvb_find_guint8(tvb, tvb_previous_offset, tvb_RBRKT, '{');
/*
if (tvb_LBRKT == -1)
return;
*/
tokenlen = (tvb_LBRKT + 1) - tvb_previous_offset;
proto_tree_add_format_text(megaco_tree, tvb, tvb_previous_offset, tokenlen);
/* Start dissecting serviceChangeParm */
tvb_previous_offset = tvb_LBRKT + 1;
while (more_params){
tvb_previous_offset = megaco_tvb_skip_wsp(tvb, tvb_previous_offset);
/* Find token length */
for (tvb_offset=tvb_previous_offset; tvb_offset < tvb_RBRKT; tvb_offset++){
if (!g_ascii_isalpha(tvb_get_guint8(tvb, tvb_offset ))){
break;
}
}
tokenlen = tvb_offset - tvb_previous_offset;
token_index = find_megaco_megaco_serviceChangeParm_names(tvb, tvb_previous_offset, tokenlen);
tvb_offset = tvb_find_guint8(tvb, tvb_offset, tvb_RBRKT, ',');
if ((tvb_offset == -1)||(tvb_offset >=tvb_RBRKT)){
more_params = FALSE;
tvb_offset = megaco_tvb_skip_wsp_return(tvb, tvb_RBRKT-1);
}
tokenlen = tvb_offset - tvb_previous_offset;
if (more_params == TRUE )
/* Include ',' */
tokenlen++;
switch(token_index){
case MEGACO_REASON_TOKEN:
/* ReasonToken EQUAL VALUE
* VALUE = quotedString / 1*(SafeChar)
*/
item = proto_tree_add_format_text(megaco_tree, tvb, tvb_previous_offset, tokenlen);
/* As the reason code ( if a digit ) can be in quoted string or 'just' digit
* look for a nine and hope for the best.
*/
tvb_current_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_RBRKT, '9');
if ( tvb_current_offset == -1)
break;
tvb_get_nstringz0(tvb,tvb_current_offset,4,ServiceChangeReason_str);
reason_valid = ws_strtoi32(ServiceChangeReason_str, NULL, &reason);
proto_item_append_text(item,"[ %s ]", val_to_str(reason, MEGACO_ServiceChangeReasons_vals,"Unknown (%u)"));
if (!reason_valid)
expert_add_info(pinfo, item, &ei_megaco_reason_invalid);
break;
case MEGACO_DELAY_TOKEN:
case MEGACO_SC_ADDR_TOKEN:
case MEGACO_MGC_ID_TOKEN:
case MEGACO_PROFILE_TOKEN:
case MEGACO_VERSION_TOKEN:
case MEGACO_METHOD_TOKEN:
/* No special dissection: fall through */
default:
/* Unknown or:
* extension = extensionParameter parmValue
* extensionParameter = "X" ("-" / "+") 1*6(ALPHA / DIGIT)
*/
proto_tree_add_format_text(megaco_tree, tvb, tvb_previous_offset, tokenlen);
break;
}
tvb_previous_offset = tvb_offset +1;
}/*End while */
/* extension = extensionParameter parmValue
* extensionParameter = "X" ("-" / "+") 1*6(ALPHA / DIGIT)
*/
/*
tokenlen = (tvb_RBRKT+1) - tvb_previous_offset;
proto_tree_add_string(megaco_tree_command_line, hf_megaco_servicechange_descriptor, tvb,
tvb_previous_offset, tokenlen,
tvb_format_text(pinfo->pool, tvb, tvb_previous_offset,
tokenlen));
*/
proto_tree_add_format_text(megaco_tree, tvb, tvb_RBRKT, 1);
}
static void
dissect_megaco_digitmapdescriptor(tvbuff_t *tvb, proto_tree *megaco_tree_command_line, gint tvb_RBRKT, gint tvb_previous_offset)
{
gint tokenlen;
tokenlen = tvb_RBRKT - tvb_previous_offset;
proto_tree_add_string(megaco_tree_command_line, hf_megaco_digitmap_descriptor, tvb,
tvb_previous_offset, tokenlen,
tvb_format_text(wmem_packet_scope(), tvb, tvb_previous_offset,
tokenlen));
}
static void
dissect_megaco_statisticsdescriptor(tvbuff_t *tvb, proto_tree *megaco_tree_command_line, gint tvb_RBRKT, gint tvb_previous_offset)
{
gint tokenlen;
proto_tree *megaco_statisticsdescriptor_tree;
proto_item *megaco_statisticsdescriptor_ti;
gint tvb_help_offset, param_start_offset, param_end_offset = 0;
tokenlen = (tvb_RBRKT+1) - tvb_previous_offset;
megaco_statisticsdescriptor_ti = proto_tree_add_item(megaco_tree_command_line,hf_megaco_statistics_descriptor,tvb,tvb_previous_offset,tokenlen, ENC_NA);
megaco_statisticsdescriptor_tree = proto_item_add_subtree(megaco_statisticsdescriptor_ti, ett_megaco_statisticsdescriptor);
tvb_help_offset = tvb_find_guint8(tvb, tvb_previous_offset+1, tvb_RBRKT, '{');
do {
param_start_offset = megaco_tvb_skip_wsp(tvb, tvb_help_offset+1);
tvb_help_offset = tvb_find_guint8(tvb, tvb_help_offset+1, tvb_RBRKT, ',');
if ( tvb_help_offset > tvb_RBRKT || tvb_help_offset == -1){
tvb_help_offset = tvb_RBRKT;
param_end_offset = megaco_tvb_skip_wsp_return(tvb, tvb_RBRKT-1);
tokenlen = param_end_offset - param_start_offset;
} else {
param_end_offset = megaco_tvb_skip_wsp(tvb, tvb_help_offset-1);
tokenlen = param_end_offset - param_start_offset+1;
}
proto_tree_add_format_text(megaco_statisticsdescriptor_tree, tvb,param_start_offset, tokenlen);
} while ( tvb_help_offset < tvb_RBRKT );
}
static void
dissect_megaco_observedeventsdescriptor(tvbuff_t *tvb, packet_info *pinfo, proto_tree *megaco_tree_command_line, gint tvb_RBRKT, gint tvb_previous_offset, proto_tree *top_tree)
{
gint tokenlen, pkg_tokenlen, tvb_current_offset, tvb_next_offset, tvb_help_offset;
gint tvb_observedevents_end_offset, tvb_LBRKT;
proto_tree *megaco_observedeventsdescriptor_tree, *megaco_observedevent_tree;
proto_item *megaco_observedeventsdescriptor_ti, *megaco_observedevent_ti, *ti;
gint requested_event_start_offset, requested_event_end_offset, param_start_offset, param_end_offset;
requested_event_start_offset = 0;
requested_event_end_offset = 0;
tvb_LBRKT = tvb_find_guint8(tvb, tvb_previous_offset, tvb_RBRKT, '{');
tvb_next_offset = tvb_LBRKT;
tokenlen = (tvb_next_offset+1) - tvb_previous_offset;
megaco_observedeventsdescriptor_ti = proto_tree_add_item(megaco_tree_command_line,hf_megaco_observedevents_descriptor,tvb,tvb_previous_offset,tokenlen, ENC_NA);
megaco_observedeventsdescriptor_tree = proto_item_add_subtree(megaco_observedeventsdescriptor_ti, ett_megaco_observedeventsdescriptor);
tvb_current_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_RBRKT, '=');
tvb_next_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_RBRKT, '{');
if ( tvb_current_offset < tvb_RBRKT && tvb_current_offset != -1 ){
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_current_offset +1);
tvb_help_offset = megaco_tvb_skip_wsp_return(tvb, tvb_next_offset-1);
tokenlen = tvb_help_offset - tvb_current_offset;
ti = proto_tree_add_uint(megaco_observedeventsdescriptor_tree, hf_megaco_requestid, tvb,
tvb_current_offset, 1,
(guint32) strtoul(tvb_format_text(pinfo->pool, tvb, tvb_current_offset, tokenlen), NULL, 10));
proto_item_set_len(ti, tokenlen);
tvb_observedevents_end_offset = tvb_RBRKT;
tvb_RBRKT = tvb_next_offset+1;
tvb_LBRKT = tvb_next_offset+1;
tvb_previous_offset = megaco_tvb_skip_wsp(tvb, tvb_next_offset+1);
do {
tvb_RBRKT = tvb_find_guint8(tvb, tvb_RBRKT+1,
tvb_observedevents_end_offset, '}');
tvb_LBRKT = tvb_find_guint8(tvb, tvb_LBRKT,
tvb_observedevents_end_offset, '{');
tvb_current_offset = tvb_find_guint8(tvb, tvb_previous_offset,
tvb_observedevents_end_offset, ',');
if (tvb_current_offset == -1 || tvb_current_offset > tvb_observedevents_end_offset){
tvb_current_offset = tvb_observedevents_end_offset;
}
/* Descriptor includes no parameters */
if ( tvb_LBRKT > tvb_current_offset || tvb_LBRKT == -1 ){
tvb_RBRKT = megaco_tvb_skip_wsp_return(tvb, tvb_current_offset-1)-1;
}
/* Descriptor includes Parameters */
if ( (tvb_current_offset > tvb_LBRKT && tvb_LBRKT != -1)){
while ( tvb_LBRKT != -1 && tvb_RBRKT > tvb_LBRKT ){
tvb_LBRKT = tvb_find_guint8(tvb, tvb_LBRKT+1,
tvb_observedevents_end_offset, '{');
if ( tvb_LBRKT < tvb_RBRKT && tvb_LBRKT != -1){
tvb_RBRKT = tvb_find_guint8(tvb, tvb_RBRKT+1,
tvb_observedevents_end_offset, '}');
}
}
}
tvb_LBRKT = tvb_help_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_observedevents_end_offset, '{');
/* if there are eventparameter */
if ( tvb_help_offset < tvb_RBRKT && tvb_help_offset != -1 ){
requested_event_start_offset = tvb_help_offset;
requested_event_end_offset = tvb_RBRKT;
tvb_help_offset = megaco_tvb_skip_wsp_return(tvb, tvb_help_offset-1);
pkg_tokenlen = tvb_help_offset - tvb_previous_offset;
tokenlen = tvb_LBRKT+1 - tvb_previous_offset;
}
/* no parameters */
else {
tokenlen = pkg_tokenlen = tvb_RBRKT+1 - tvb_previous_offset;
}
megaco_observedevent_ti = proto_tree_add_format_text(megaco_tree_command_line, tvb, tvb_previous_offset, tokenlen);
megaco_observedevent_tree = proto_item_add_subtree(megaco_observedevent_ti, ett_megaco_observedevent);
proto_tree_add_item(megaco_observedevent_tree,hf_megaco_pkgdname,tvb,tvb_previous_offset,pkg_tokenlen, ENC_UTF_8);
if ( tvb_help_offset < tvb_RBRKT && tvb_help_offset != -1 ){
requested_event_start_offset = megaco_tvb_skip_wsp(tvb, requested_event_start_offset +1)-1;
requested_event_end_offset = megaco_tvb_skip_wsp_return(tvb, requested_event_end_offset-1);
tvb_help_offset = requested_event_start_offset;
do {
param_start_offset = megaco_tvb_skip_wsp(tvb, tvb_help_offset+1);
tvb_help_offset = tvb_find_guint8(tvb, tvb_help_offset+1,requested_event_end_offset, ',');
if ( tvb_help_offset > requested_event_end_offset || tvb_help_offset == -1){
tvb_help_offset = requested_event_end_offset;
}
param_end_offset = megaco_tvb_skip_wsp(tvb, tvb_help_offset-1);
tokenlen = param_end_offset - param_start_offset+1;
if(!tvb_strneql(tvb, param_start_offset, "h245", 4)){
dissect_megaco_h245(tvb, pinfo, megaco_tree_command_line, param_start_offset, tokenlen, top_tree);
} else {
proto_tree_add_format_text(megaco_tree_command_line, tvb, param_start_offset, tokenlen);
}
} while ( tvb_help_offset < requested_event_end_offset );
}
tvb_previous_offset = tvb_current_offset;
tvb_current_offset = tvb_find_guint8(tvb, tvb_RBRKT,
tvb_observedevents_end_offset, ',');
if (tvb_current_offset == -1 || tvb_current_offset > tvb_observedevents_end_offset ){
tvb_current_offset = tvb_observedevents_end_offset;
}
if (tvb_current_offset < tvb_previous_offset) {
expert_add_info_format(pinfo, megaco_observedevent_ti, &ei_megaco_parse_error, "Parse error: Invalid offset");
return;
}
tvb_previous_offset = megaco_tvb_skip_wsp(tvb, tvb_current_offset+1);
tvb_LBRKT = tvb_previous_offset;
tvb_RBRKT = tvb_previous_offset;
/* Print the trailing '}' (raw formatting removed) */
/* proto_tree_add_format_text(megaco_tree_command_line, tvb, tvb_observedevents_end_offset, 1); */
} while ( tvb_current_offset < tvb_observedevents_end_offset );
}
}
static void
dissect_megaco_topologydescriptor(tvbuff_t *tvb, proto_tree *megaco_tree_command_line, gint tvb_RBRKT, gint tvb_previous_offset)
{
gint tokenlen;
tokenlen = (tvb_RBRKT+1) - tvb_previous_offset;
proto_tree_add_string(megaco_tree_command_line, hf_megaco_topology_descriptor, tvb,
tvb_previous_offset, tokenlen,
tvb_format_text_wsp(wmem_packet_scope(), tvb, tvb_previous_offset,
tokenlen));
}
static void
dissect_megaco_Packagesdescriptor(tvbuff_t *tvb, proto_tree *megaco_tree_command_line, gint tvb_RBRKT, gint tvb_previous_offset)
{
gint tokenlen, tvb_current_offset, tvb_next_offset, tvb_help_offset;
gint tvb_packages_end_offset, tvb_LBRKT;
proto_tree *megaco_packagesdescriptor_tree;
proto_item *megaco_packagesdescriptor_ti, *ti;
tokenlen = (tvb_RBRKT+1) - tvb_previous_offset;
megaco_packagesdescriptor_ti = proto_tree_add_item(megaco_tree_command_line,hf_megaco_packages_descriptor,tvb,tvb_previous_offset,tokenlen, ENC_UTF_8);
megaco_packagesdescriptor_tree = proto_item_add_subtree(megaco_packagesdescriptor_ti, ett_megaco_packagesdescriptor);
tvb_current_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_RBRKT, '=');
tvb_next_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_RBRKT, '{');
if ( tvb_current_offset < tvb_RBRKT && tvb_current_offset != -1 ){
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_current_offset +1);
tvb_help_offset = megaco_tvb_skip_wsp_return(tvb, tvb_next_offset-1);
tokenlen = tvb_help_offset - tvb_current_offset;
ti = proto_tree_add_uint(megaco_packagesdescriptor_tree, hf_megaco_requestid, tvb,
tvb_current_offset, 1,
(guint32) strtoul(tvb_format_text(wmem_packet_scope(), tvb, tvb_current_offset, tokenlen), NULL, 10));
proto_item_set_len(ti, tokenlen);
tvb_packages_end_offset = tvb_RBRKT;
tvb_RBRKT = tvb_next_offset+1;
tvb_LBRKT = tvb_next_offset+1;
tvb_previous_offset = megaco_tvb_skip_wsp(tvb, tvb_next_offset+1);
do {
tvb_RBRKT = tvb_find_guint8(tvb, tvb_RBRKT+1,
tvb_packages_end_offset, '}');
tvb_LBRKT = tvb_find_guint8(tvb, tvb_LBRKT,
tvb_packages_end_offset, '{');
tvb_current_offset = tvb_find_guint8(tvb, tvb_previous_offset,
tvb_packages_end_offset, ',');
if (tvb_current_offset == -1 || tvb_current_offset > tvb_packages_end_offset){
tvb_current_offset = tvb_packages_end_offset;
}
/* Descriptor includes no parameters */
if ( tvb_LBRKT > tvb_current_offset || tvb_LBRKT == -1 ){
tvb_RBRKT = megaco_tvb_skip_wsp_return(tvb, tvb_current_offset-1)-1;
}
/* Descriptor includes Parameters */
if ( (tvb_current_offset > tvb_LBRKT && tvb_LBRKT != -1)){
while ( tvb_LBRKT != -1 && tvb_RBRKT > tvb_LBRKT ){
tvb_LBRKT = tvb_find_guint8(tvb, tvb_LBRKT+1,
tvb_packages_end_offset, '{');
if ( tvb_LBRKT < tvb_RBRKT && tvb_LBRKT != -1)
tvb_RBRKT = tvb_find_guint8(tvb, tvb_RBRKT+1,
tvb_packages_end_offset, '}');
}
}
tokenlen = tvb_RBRKT+1 - tvb_previous_offset;
proto_tree_add_format_text(megaco_packagesdescriptor_tree, tvb, tvb_previous_offset, tokenlen);
tvb_current_offset = tvb_find_guint8(tvb, tvb_RBRKT,
tvb_packages_end_offset, ',');
if (tvb_current_offset == -1 || tvb_current_offset > tvb_packages_end_offset ){
tvb_current_offset = tvb_packages_end_offset;
}
tvb_previous_offset = megaco_tvb_skip_wsp(tvb, tvb_current_offset+1);
tvb_LBRKT = tvb_previous_offset;
tvb_RBRKT = tvb_previous_offset;
} while ( tvb_current_offset < tvb_packages_end_offset );
}
}
/* The list of error code values is fetched from http://www.iana.org/assignments/megaco-h248 */
/* 2003-08-28 */
static const value_string MEGACO_error_code_vals[] = {
{400, "Syntax error in message"},
{401, "Protocol Error"},
{402, "Unauthorized"},
{403, "Syntax error in transaction request"},
{406, "Version Not Supported"},
{410, "Incorrect identifier"},
{411, "The transaction refers to an unknown ContextId"},
{412, "No ContextIDs available"},
{421, "Unknown action or illegal combination of actions"},
{422, "Syntax Error in Action"},
{430, "Unknown TerminationID"},
{431, "No TerminationID matched a wildcard"},
{432, "Out of TerminationIDs or No TerminationID available"},
{433, "TerminationID is already in a Context"},
{434, "Max number of Terminations in a Context exceeded"},
{435, "Termination ID is not in specified Context"},
{440, "Unsupported or unknown Package"},
{441, "Missing Remote or Local Descriptor"},
{442, "Syntax Error in Command"},
{443, "Unsupported or Unknown Command"},
{444, "Unsupported or Unknown Descriptor"},
{445, "Unsupported or Unknown Property"},
{446, "Unsupported or Unknown Parameter"},
{447, "Descriptor not legal in this command"},
{448, "Descriptor appears twice in a command"},
{450, "No such property in this package"},
{451, "No such event in this package"},
{452, "No such signal in this package"},
{453, "No such statistic in this package"},
{454, "No such parameter value in this package"},
{455, "Property illegal in this Descriptor"},
{456, "Property appears twice in this Descriptor"},
{457, "Missing parameter in signal or event"},
{458, "Unexpected Event/Request ID"},
{459, "Unsupported or Unknown Profile"},
{471, "Implied Add for Multiplex failure"},
{500, "Internal software Failure in MG"},
{501, "Not Implemented"},
{502, "Not ready."},
{503, "Service Unavailable"},
{504, "Command Received from unauthorized entity"},
{505, "Transaction Request Received before a Service Change Reply has been received"},
{506, "Number of Transaction Pendings Exceeded"},
{510, "Insufficient resources"},
{512, "Media Gateway unequipped to detect requested Event"},
{513, "Media Gateway unequipped to generate requested Signals"},
{514, "Media Gateway cannot send the specified announcement"},
{515, "Unsupported Media Type"},
{517, "Unsupported or invalid mode"},
{518, "Event buffer full"},
{519, "Out of space to store digit map"},
{520, "Digit Map undefined in the MG"},
{521, "Termination is ServiceChanging"},
{526, "Insufficient bandwidth"},
{529, "Internal hardware failure in MG"},
{530, "Temporary Network failure"},
{531, "Permanent Network failure"},
{532, "Audited Property, Statistic, Event or Signal does not exist"},
{533, "Response exceeds maximum transport PDU size"},
{534, "Illegal write or read only property"},
{540, "Unexpected initial hook state"},
{581, "Does Not Exist"},
{600, "Illegal syntax within an announcement specification"},
{601, "Variable type not supported"},
{602, "Variable value out of range"},
{603, "Category not supported"},
{604, "Selector type not supported"},
{605, "Selector value not supported"},
{606, "Unknown segment ID"},
{607, "Mismatch between play specification and provisioned data"},
{608, "Provisioning error"},
{609, "Invalid offset"},
{610, "No free segment IDs"},
{611, "Temporary segment not found"},
{612, "Segment in use"},
{613, "ISP port limit overrun"},
{614, "No modems available"},
{615, "Calling number unacceptable"},
{616, "Called number unacceptable"},
{ 0, NULL }
};
static void
dissect_megaco_errordescriptor(tvbuff_t *tvb, packet_info* pinfo, proto_tree *megaco_tree_command_line,
gint tvb_RBRKT, gint tvb_previous_offset)
{
gint tokenlen;
gint error_code;
guint8 error[4];
gint tvb_current_offset;
proto_item* item;
proto_tree* error_tree;
gboolean error_code_valid;
tvb_current_offset = tvb_find_guint8(tvb, tvb_previous_offset , tvb_RBRKT, '=');
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_current_offset +1);
tokenlen = (tvb_RBRKT) - tvb_previous_offset+1;
item = proto_tree_add_item(megaco_tree_command_line, hf_megaco_error_descriptor, tvb,
tvb_previous_offset, tokenlen, ENC_NA);
error_tree = proto_item_add_subtree(item, ett_megaco_error_descriptor);
/* Get the error code */
tvb_get_nstringz0(tvb,tvb_current_offset,4,error);
error_code_valid = ws_strtoi32(error, NULL, &error_code);
item = proto_tree_add_uint(error_tree, hf_megaco_error_code, tvb, tvb_current_offset, 3, error_code);
if (!error_code_valid)
expert_add_info(pinfo, item, &ei_megaco_error_code_invalid);
/* Get the error string (even though we have a value_string that should match) */
tvb_previous_offset = tvb_find_guint8(tvb, tvb_current_offset, tvb_RBRKT, '\"');
tvb_current_offset = tvb_find_guint8(tvb, tvb_previous_offset+1, tvb_RBRKT, '\"');
tokenlen = tvb_current_offset - tvb_previous_offset-1;
proto_tree_add_item(error_tree, hf_megaco_error_string, tvb, tvb_previous_offset+1, tokenlen, ENC_UTF_8);
}
static void
dissect_megaco_TerminationStatedescriptor(tvbuff_t *tvb, proto_tree *megaco_mediadescriptor_tree, gint tvb_next_offset, gint tvb_current_offset)
{
gint tokenlen;
gint tvb_offset;
guint8 tempchar;
proto_tree *megaco_TerminationState_tree, *megaco_TerminationState_ti;
tvb_offset = tvb_find_guint8(tvb, tvb_current_offset , tvb_next_offset, '=');
tokenlen = tvb_next_offset - tvb_current_offset;
megaco_TerminationState_ti = proto_tree_add_item(megaco_mediadescriptor_tree,hf_megaco_TerminationState_descriptor,tvb,tvb_current_offset,tokenlen, ENC_NA);
megaco_TerminationState_tree = proto_item_add_subtree(megaco_TerminationState_ti, ett_megaco_TerminationState);
while ( tvb_offset < tvb_next_offset && tvb_offset != -1 ){
tempchar = tvb_get_guint8(tvb, tvb_current_offset);
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
if ( (tempchar >= 'a')&& (tempchar <= 'z'))
tempchar = tempchar - 0x20;
switch ( tempchar ){
case 'S':
tvb_offset = tvb_find_guint8(tvb, tvb_current_offset , tvb_offset, ',');
if ( tvb_offset == -1 || tvb_offset > tvb_next_offset ){
tvb_offset = tvb_next_offset;
}
tokenlen = tvb_offset - tvb_current_offset;
proto_tree_add_string(megaco_TerminationState_tree, hf_megaco_Service_State, tvb,
tvb_current_offset, tokenlen,
tvb_format_text(wmem_packet_scope(), tvb, tvb_current_offset,
tokenlen));
break;
case 'B':
tvb_offset = tvb_find_guint8(tvb, tvb_current_offset , tvb_offset, ',');
if ( tvb_offset == -1 || tvb_offset > tvb_next_offset ){
tvb_offset = tvb_next_offset;
}
tokenlen = tvb_offset - tvb_current_offset;
proto_tree_add_string(megaco_TerminationState_tree, hf_megaco_Event_Buffer_Control, tvb,
tvb_current_offset, tokenlen,
tvb_format_text(wmem_packet_scope(), tvb, tvb_current_offset,
tokenlen));
break;
case 'E':
tvb_offset = tvb_find_guint8(tvb, tvb_current_offset , tvb_offset, ',');
if ( tvb_offset == -1 || tvb_offset > tvb_next_offset ){
tvb_offset = tvb_next_offset;
}
tokenlen = tvb_offset - tvb_current_offset;
proto_tree_add_string(megaco_TerminationState_tree, hf_megaco_Event_Buffer_Control, tvb,
tvb_current_offset, tokenlen,
tvb_format_text(wmem_packet_scope(), tvb, tvb_current_offset,
tokenlen));
break;
default:
tvb_offset = tvb_find_guint8(tvb, tvb_current_offset , tvb_offset, ',');
if ( tvb_offset == -1 || tvb_offset > tvb_next_offset ){
tvb_offset = tvb_next_offset;
}
tokenlen = tvb_offset - tvb_current_offset;
proto_tree_add_format_text(megaco_TerminationState_tree, tvb, tvb_current_offset, tokenlen);
break;
}
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
tvb_offset = tvb_find_guint8(tvb, tvb_current_offset , tvb_next_offset, '=');
}
/* (raw formatting removed)
proto_tree_add_format_text(megaco_mediadescriptor_tree, tvb, tvb_next_offset, 1); */
}
static void
dissect_megaco_LocalRemotedescriptor(tvbuff_t *tvb, proto_tree *megaco_mediadescriptor_tree, packet_info *pinfo,
gint tvb_next_offset, gint tvb_current_offset, guint32 context, gboolean is_local)
{
gint tokenlen;
tvbuff_t *next_tvb;
http_message_info_t message_info = { SIP_DATA, NULL, NULL, NULL };
sdp_setup_info_t setup_info;
/* Only fill in the info when we have valid contex */
if ((context != 0) && (context < 0xfffffffe)) {
setup_info.hf_id = hf_megaco_Context;
setup_info.hf_type = SDP_TRACE_ID_HF_TYPE_GUINT32;
if (!sip_hide_generated_call_ids) {
setup_info.add_hidden = FALSE;
} else {
setup_info.add_hidden = prefs_get_bool_value(sip_hide_generated_call_ids, pref_current);
}
setup_info.trace_id.num = context;
message_info.data = &setup_info;
}
proto_tree *megaco_localdescriptor_tree;
proto_item *megaco_localdescriptor_item;
tokenlen = tvb_next_offset - tvb_current_offset;
if (is_local) {
megaco_localdescriptor_item = proto_tree_add_item(megaco_mediadescriptor_tree, hf_megaco_Local_descriptor, tvb, tvb_current_offset, tokenlen, ENC_NA);
megaco_localdescriptor_tree = proto_item_add_subtree(megaco_localdescriptor_item, ett_megaco_Localdescriptor);
} else {
megaco_localdescriptor_item = proto_tree_add_item(megaco_mediadescriptor_tree, hf_megaco_Remote_descriptor, tvb, tvb_current_offset, tokenlen, ENC_NA);
megaco_localdescriptor_tree = proto_item_add_subtree(megaco_localdescriptor_item, ett_megaco_Remotedescriptor);
}
if ( tokenlen > 3 ){
next_tvb = tvb_new_subset_length(tvb, tvb_current_offset, tokenlen);
call_dissector_with_data(sdp_handle, next_tvb, pinfo, megaco_localdescriptor_tree, &message_info);
}
}
/*
* localControlDescriptor = LocalControlToken LBRKT localParm
* *(COMMA localParm) RBRKT
* ; at-most-once per item
* localParm = ( streamMode / propertyParm / reservedValueMode / reservedGroupMode )
*/
#define MEGACO_MODETOKEN 1
#define MEGACO_RESERVEDVALUETOKEN 2
#define MEGACO_RESERVEDGROUPTOKEN 3
#define MEGACO_H324_H223CAPR 4
#define MEGACO_H324_MUXTBL_IN 5
#define MEGACO_H324_MUXTBL_OUT 6
#define MEGACO_DS_DSCP 7
#define MEGACO_GM_SAF 8
#define MEGACO_GM_SAM 9
#define MEGACO_GM_SPF 10
#define MEGACO_GM_SPR 11
#define MEGACO_GM_ESAS 12
#define MEGACO_GM_LSA 13
#define MEGACO_GM_ESPS 14
#define MEGACO_GM_LSP 15
#define MEGACO_GM_RSB 16
#define MEGACO_TMAN_POL 17
#define MEGACO_TMAN_SDR 18
#define MEGACO_TMAN_MBS 19
#define MEGACO_TMAN_PDR 20
#define MEGACO_TMAN_DVT 21
#define MEGACO_IPDC_REALM 22
static const megaco_tokens_t megaco_localParam_names[] = {
{ "Unknown-token", NULL }, /* 0 Pad so that the real headers start at index 1 */
/* streamMode */
{ "Mode", "MO" }, /* 1 */
{ "ReservedValue", "RV" }, /* 2 */
{ "ReservedGroup", "RG" }, /* 3 */
/* propertyParm = pkgdName parmValue
* Add more package names as needed.
*/
{ "h324/h223capr", NULL }, /* 4 */
{ "h324/muxtbl_in", NULL }, /* 5 */
{ "h324/muxtbl_out", NULL }, /* 6 */
{ "ds/dscp", NULL }, /* 7 */
{ "gm/saf", NULL }, /* 8 */
{ "gm/sam", NULL }, /* 9 */
{ "gm/spf", NULL }, /* 10 */
{ "gm/spr", NULL }, /* 11 */
{ "gm/esas", NULL }, /* 12 */
{ "gm/lsa", NULL }, /* 13 */
{ "gm/esps", NULL }, /* 14 */
{ "gm/lsp", NULL }, /* 15 */
{ "gm/rsb", NULL }, /* 16 */
{ "tman/pol", NULL }, /* 17 */
{ "tman/sdr", NULL }, /* 18 */
{ "tman/mbs", NULL }, /* 19 */
{ "tman/pdr", NULL }, /* 20 */
{ "tman/dvt", NULL }, /* 21 */
{ "ipdc/realm", NULL }, /* 22 */
};
/* Returns index of megaco_tokens_t */
static gint find_megaco_localParam_names(tvbuff_t *tvb, int offset, guint header_len)
{
guint i;
for (i = 1; i < array_length(megaco_localParam_names); i++) {
if (header_len == strlen(megaco_localParam_names[i].name) &&
tvb_strncaseeql(tvb, offset, megaco_localParam_names[i].name, header_len) == 0)
return i;
if (megaco_localParam_names[i].compact_name != NULL &&
header_len == strlen(megaco_localParam_names[i].compact_name) &&
tvb_strncaseeql(tvb, offset, megaco_localParam_names[i].compact_name, header_len) == 0)
return i;
}
return -1;
}
static void
dissect_megaco_LocalControldescriptor(tvbuff_t *tvb, proto_tree *megaco_mediadescriptor_tree, packet_info *pinfo, gint tvb_next_offset, gint tvb_current_offset, proto_tree *top_tree)
{
gint tokenlen;
guint token_name_len;
gint tvb_offset = 0,tvb_help_offset;
gint token_index = 0;
gchar *msg;
proto_item* item;
guint8 code_str[3];
proto_tree *megaco_LocalControl_tree;
proto_item *megaco_LocalControl_item;
tokenlen = tvb_next_offset - tvb_current_offset;
megaco_LocalControl_item = proto_tree_add_item(megaco_mediadescriptor_tree, hf_megaco_LocalControl_descriptor, tvb, tvb_current_offset, tokenlen, ENC_NA);
megaco_LocalControl_tree = proto_item_add_subtree(megaco_LocalControl_item, ett_megaco_LocalControldescriptor);
while ( tvb_offset < tvb_next_offset && tvb_offset != -1 ){
tvb_help_offset = tvb_current_offset;
/*
* Find local parameter name
* localParm = ( streamMode / propertyParm / reservedValueMode / reservedGroupMode )
* pkgdName = (PackageName SLASH ItemID) ;specific item
* / (PackageName SLASH "*") ;all events in package
* / ("*" SLASH "*") ; all events supported by the MG
*/
/* Find token length */
for (tvb_offset=tvb_current_offset; tvb_offset < tvb_next_offset; tvb_offset++){
guint8 octet;
octet = tvb_get_guint8(tvb, tvb_offset);
if (!g_ascii_isalnum(octet)){
if ((octet!='/')&&(octet!='_')){
break;
}
}
}
token_name_len = tvb_offset - tvb_current_offset;
/* Debug Code
proto_tree_add_format_text(megaco_LocalControl_tree, tvb, tvb_current_offset, token_name_len);
*/
token_index = find_megaco_localParam_names(tvb, tvb_current_offset, token_name_len);
/* Find start of parameter value */
tvb_offset = tvb_find_guint8(tvb, tvb_offset , tvb_next_offset, '=');
if (tvb_offset == -1) {
expert_add_info(pinfo, megaco_LocalControl_item, &ei_megaco_parse_error);
return;
}
/* Start search after '=' in case there is no SP*/
tvb_offset++;
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset);
/* find if there are more parameters or not */
tvb_offset = tvb_find_guint8(tvb, tvb_current_offset , tvb_offset, ',');
if ( tvb_offset < 0 || tvb_offset > tvb_next_offset ){
tvb_offset = tvb_next_offset;
}
tokenlen = megaco_tvb_skip_wsp_return(tvb,tvb_offset-1) - tvb_current_offset;
/* Debug Code
proto_tree_add_format_text(megaco_LocalControl_tree, tvb, tvb_current_offset, tokenlen);
*/
switch ( token_index ){
case MEGACO_MODETOKEN: /* Mode */
proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_mode, tvb,
tvb_help_offset, tvb_offset-tvb_help_offset,
tvb_format_text(pinfo->pool, tvb, tvb_current_offset,
tokenlen));
col_append_fstr(pinfo->cinfo, COL_INFO, " (Mode:%s)",tvb_format_text(pinfo->pool, tvb, tvb_current_offset,tokenlen));
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
break;
case MEGACO_RESERVEDVALUETOKEN: /* ReservedValue */
proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_reserve_value, tvb,
tvb_help_offset, tvb_offset-tvb_help_offset,
tvb_format_text(pinfo->pool, tvb, tvb_current_offset, tokenlen));
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
break;
case MEGACO_RESERVEDGROUPTOKEN: /* ReservedGroup */
proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_reserve_group, tvb,
tvb_help_offset, tvb_offset-tvb_help_offset,
tvb_format_text(pinfo->pool, tvb, tvb_current_offset, tokenlen));
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
break;
case MEGACO_H324_H223CAPR: /* h324/h223capr */
proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_h324_h223capr, tvb,
tvb_help_offset, tvb_offset-tvb_help_offset,
tvb_format_text(pinfo->pool, tvb, tvb_current_offset, tokenlen));
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
tokenlen = tvb_offset - tvb_help_offset;
msg=tvb_format_text(pinfo->pool, tvb,tvb_help_offset, tokenlen);
dissect_megaco_h324_h223caprn(tvb, pinfo, megaco_mediadescriptor_tree, tvb_help_offset, tokenlen, msg);
break;
case MEGACO_H324_MUXTBL_IN: /* h324/muxtbl_in */
proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_h324_muxtbl_in, tvb,
tvb_help_offset, tvb_offset-tvb_help_offset,
tvb_format_text(pinfo->pool, tvb, tvb_current_offset, tokenlen));
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
tokenlen = tvb_offset - tvb_help_offset;
/* Call the existing routine with tree = NULL to avoid an entry to the tree */
dissect_megaco_h245(tvb, pinfo, NULL, tvb_help_offset, tokenlen, top_tree);
break;
case MEGACO_H324_MUXTBL_OUT:
proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_h324_muxtbl_out, tvb,
tvb_current_offset, tokenlen,
tvb_format_text(pinfo->pool, tvb, tvb_current_offset,
tokenlen));
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
tokenlen = tvb_offset - tvb_help_offset;
/* Call the existing routine with tree = NULL to avoid an entry to the tree */
dissect_megaco_h245(tvb, pinfo, NULL, tvb_help_offset, tokenlen, top_tree);
break;
case MEGACO_DS_DSCP:
tvb_get_nstringz0(tvb,tvb_current_offset,3,code_str);
item = proto_tree_add_uint(megaco_LocalControl_tree, hf_megaco_ds_dscp, tvb,
tvb_help_offset, 1, (guint32) strtoul(code_str,NULL,16));
proto_item_set_len(item, tvb_offset-tvb_help_offset);
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
break;
case MEGACO_GM_SAF:
proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_gm_saf, tvb,
tvb_help_offset, tvb_offset-tvb_help_offset, tvb_format_text(pinfo->pool, tvb, tvb_current_offset, tokenlen));
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
break;
case MEGACO_GM_SAM:
proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_gm_sam, tvb,
tvb_help_offset, tvb_offset-tvb_help_offset, tvb_format_text(pinfo->pool, tvb, tvb_current_offset, tokenlen));
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
break;
case MEGACO_GM_SPF:
proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_gm_spf, tvb,
tvb_help_offset, tvb_offset-tvb_help_offset, tvb_format_text(pinfo->pool, tvb, tvb_current_offset, tokenlen));
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
break;
case MEGACO_GM_SPR:
proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_gm_spr, tvb,
tvb_help_offset, tvb_offset-tvb_help_offset, tvb_format_text(pinfo->pool, tvb, tvb_current_offset, tokenlen));
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
break;
case MEGACO_GM_ESAS:
proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_gm_esas, tvb,
tvb_help_offset, tvb_offset-tvb_help_offset, tvb_format_text(pinfo->pool, tvb, tvb_current_offset, tokenlen));
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
break;
case MEGACO_GM_RSB:
proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_gm_rsb, tvb,
tvb_help_offset, tvb_offset - tvb_help_offset, tvb_format_text(pinfo->pool, tvb, tvb_current_offset, tokenlen));
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset + 1);
break;
case MEGACO_TMAN_POL:
proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_tman_pol, tvb,
tvb_help_offset, tvb_offset-tvb_help_offset, tvb_format_text(pinfo->pool, tvb, tvb_current_offset, tokenlen));
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
break;
case MEGACO_TMAN_SDR:
{
gint32 sdr;
gboolean sdr_valid;
proto_item* pi;
sdr_valid = ws_strtoi32(tvb_format_text(pinfo->pool, tvb, tvb_current_offset, tokenlen), NULL, &sdr);
pi =proto_tree_add_int(megaco_LocalControl_tree, hf_megaco_tman_sdr, tvb, tvb_help_offset,
tvb_offset - tvb_help_offset, sdr);
proto_item_append_text(pi, " [%i b/s]", sdr*8);
if (!sdr_valid) {
expert_add_info(pinfo, pi, &ei_megaco_invalid_sdr);
}
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset + 1);
}
break;
case MEGACO_TMAN_MBS:
proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_tman_mbs, tvb,
tvb_help_offset, tvb_offset-tvb_help_offset, tvb_format_text(pinfo->pool, tvb, tvb_current_offset, tokenlen));
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
break;
case MEGACO_TMAN_PDR:
proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_tman_pdr, tvb,
tvb_help_offset, tvb_offset-tvb_help_offset, tvb_format_text(pinfo->pool, tvb, tvb_current_offset, tokenlen));
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
break;
case MEGACO_TMAN_DVT:
proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_tman_dvt, tvb,
tvb_help_offset, tvb_offset-tvb_help_offset, tvb_format_text(pinfo->pool, tvb, tvb_current_offset, tokenlen));
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
break;
case MEGACO_IPDC_REALM:
proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_ipdc_realm, tvb,
tvb_help_offset, tvb_offset-tvb_help_offset, tvb_format_text(pinfo->pool, tvb, tvb_current_offset, tokenlen));
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
break;
default:
tokenlen = tvb_offset - tvb_help_offset;
proto_tree_add_format_text(megaco_LocalControl_tree, tvb, tvb_help_offset, tokenlen);
tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
break;
}
}
}
static void
dissect_megaco_descriptors(tvbuff_t *tvb, proto_tree *megaco_command_tree, packet_info *pinfo, gint tvb_descriptors_start_offset,
gint tvb_descriptors_end_offset, proto_tree *top_tree, guint32 context)
{
gint tvb_len, token_index, tvb_offset, temp_offset;
gint tvb_current_offset,tvb_previous_offset,save_offset,tokenlen;
gint tvb_RBRKT, tvb_LBRKT;
proto_tree* descriptor_tree;
proto_item* descriptor_item;
tvb_len = tvb_reported_length(tvb);
descriptor_tree = proto_tree_add_subtree(megaco_command_tree, tvb, tvb_descriptors_start_offset,
tvb_descriptors_end_offset-tvb_descriptors_start_offset, ett_megaco_descriptors, &descriptor_item, "Descriptors");
tvb_LBRKT = megaco_tvb_skip_wsp(tvb, tvb_descriptors_start_offset +1);
tvb_previous_offset = tvb_LBRKT;
tvb_RBRKT = tvb_descriptors_start_offset;
do {
tvb_RBRKT = tvb_find_guint8(tvb, tvb_RBRKT+1,
tvb_len, '}');
tvb_LBRKT = tvb_find_guint8(tvb, tvb_LBRKT,
tvb_len, '{');
tvb_current_offset = tvb_find_guint8(tvb, tvb_previous_offset,
tvb_len, ',');
if (tvb_current_offset == -1 || tvb_current_offset > tvb_descriptors_end_offset){
tvb_current_offset = tvb_descriptors_end_offset;
}
if (tvb_current_offset <= tvb_previous_offset) {
expert_add_info_format(pinfo, descriptor_item, &ei_megaco_parse_error, "Parse error: Invalid offset");
return;
}
/* Descriptor includes no parameters */
if ( tvb_LBRKT > tvb_current_offset || tvb_LBRKT == -1 ){
if ( tvb_current_offset > tvb_RBRKT ){
tvb_current_offset = tvb_RBRKT;
}
tvb_RBRKT = megaco_tvb_skip_wsp_return(tvb, tvb_current_offset-1)-1;
}
/* Descriptor includes Parameters */
if ( (tvb_current_offset > tvb_LBRKT && tvb_LBRKT != -1)){
while ( tvb_LBRKT != -1 && tvb_RBRKT > tvb_LBRKT ){
tvb_LBRKT = tvb_find_guint8(tvb, tvb_LBRKT+1,
tvb_len, '{');
if ( tvb_LBRKT < tvb_RBRKT && tvb_LBRKT != -1)
tvb_RBRKT = tvb_find_guint8(tvb, tvb_RBRKT+1,tvb_len, '}');
}
}
/* Find token length */
for (tvb_offset=tvb_previous_offset; tvb_offset < tvb_descriptors_end_offset -1; tvb_offset++){
if (!g_ascii_isalpha(tvb_get_guint8(tvb, tvb_offset ))){
break;
}
}
tokenlen = tvb_offset - tvb_previous_offset;
token_index = find_megaco_descriptors_names(tvb, tvb_previous_offset, tokenlen);
if (tvb_RBRKT > tvb_descriptors_end_offset)
tvb_RBRKT = tvb_descriptors_end_offset;
switch ( token_index ){
case MEGACO_MODEM_TOKEN:
dissect_megaco_modemdescriptor(tvb, descriptor_tree, tvb_RBRKT, tvb_previous_offset);
break;
case MEGACO_MUX_TOKEN:
dissect_megaco_multiplexdescriptor(tvb, descriptor_tree, tvb_RBRKT, tvb_previous_offset);
break;
case MEGACO_MEDIA_TOKEN:
/*TODO: Move this to the top when all branches fixed !!!*/
temp_offset = tvb_find_guint8(tvb, tvb_previous_offset,tvb_descriptors_end_offset, '{');
save_offset = tvb_previous_offset;
tvb_previous_offset = megaco_tvb_skip_wsp(tvb, temp_offset +1);
dissect_megaco_mediadescriptor(tvb, descriptor_tree, pinfo, tvb_RBRKT, tvb_previous_offset, save_offset, top_tree, context);
break;
case MEGACO_SIGNALS_TOKEN:
dissect_megaco_signaldescriptor(tvb, pinfo, descriptor_tree, tvb_RBRKT, tvb_previous_offset, top_tree);
break;
case MEGACO_SERVICES_TOKEN:
dissect_megaco_servicechangedescriptor(tvb, pinfo, descriptor_tree, tvb_RBRKT, tvb_previous_offset);
break;
case MEGACO_STATS_TOKEN:
dissect_megaco_statisticsdescriptor(tvb, descriptor_tree, tvb_RBRKT, tvb_previous_offset);
break;
case MEGACO_ERROR_TOKEN:
dissect_megaco_errordescriptor(tvb, pinfo, descriptor_tree, tvb_RBRKT, tvb_previous_offset);
break;
case MEGACO_EVENTS_TOKEN:
dissect_megaco_eventsdescriptor(tvb, pinfo, descriptor_tree, tvb_RBRKT, tvb_previous_offset, top_tree);
break;
case MEGACO_AUDIT_TOKEN:
dissect_megaco_auditdescriptor(tvb, descriptor_tree, pinfo, tvb_RBRKT, tvb_previous_offset);
break;
case MEGACO_DIGITMAP_TOKEN:
dissect_megaco_digitmapdescriptor(tvb, descriptor_tree, tvb_RBRKT, tvb_previous_offset);
break;
case MEGACO_OE_TOKEN:
/* ObservedEventsToken */
dissect_megaco_observedeventsdescriptor(tvb, pinfo, descriptor_tree, tvb_RBRKT, tvb_previous_offset, top_tree);
break;
case MEGACO_TOPOLOGY_TOKEN:
dissect_megaco_topologydescriptor(tvb, descriptor_tree, tvb_RBRKT, tvb_previous_offset);
break;
case MEGACO_PACKAGES_TOKEN:
dissect_megaco_Packagesdescriptor(tvb, descriptor_tree, tvb_RBRKT, tvb_previous_offset);
break;
default:
tokenlen = (tvb_RBRKT+1) - tvb_previous_offset;
proto_tree_add_expert(descriptor_tree, pinfo, &ei_megaco_no_descriptor, tvb, tvb_previous_offset, tokenlen);
break;
}
tvb_current_offset = tvb_find_guint8(tvb, tvb_RBRKT, tvb_len, ',');
if (tvb_current_offset == -1 || tvb_descriptors_end_offset < tvb_current_offset){
tvb_current_offset = tvb_descriptors_end_offset;
}
tvb_previous_offset = megaco_tvb_skip_wsp(tvb, tvb_current_offset+1);
tvb_LBRKT = tvb_previous_offset;
tvb_RBRKT = tvb_previous_offset;
} while ( tvb_current_offset < tvb_descriptors_end_offset );
}
/* Copied from MGCP dissector, prints whole message in raw text */
static void tvb_raw_text_add(tvbuff_t *tvb, proto_tree *tree){
gint tvb_linebegin,tvb_lineend,linelen;
proto_tree* text_tree;
tvb_linebegin = 0;
if (tree) {
text_tree = proto_tree_add_subtree(tree, tvb, 0, -1, ett_megaco_raw_text, NULL, "-------------- (RAW text output) ---------------");
do {
linelen = tvb_find_line_end(tvb,tvb_linebegin,-1,&tvb_lineend,FALSE);
proto_tree_add_format_wsp_text(text_tree, tvb, tvb_linebegin, linelen);
tvb_linebegin = tvb_lineend;
} while (tvb_offset_exists(tvb, tvb_lineend) && linelen > 0);
}
}
/*
* megaco_tvb_skip_wsp - Returns the position in tvb of the first non-whitespace
* character following offset or offset + maxlength -1 whichever
* is smaller.
*
* Parameters:
* tvb - The tvbuff in which we are skipping whitespaces, tab and end_of_line characters.
* offset - The offset in tvb from which we begin trying to skip whitespace.
*
* Returns: The position in tvb of the first non-whitespace
*/
static gint megaco_tvb_skip_wsp(tvbuff_t* tvb, gint offset ){
gint counter = offset;
gint end = tvb_reported_length(tvb);
for(counter = offset; counter < end &&
(g_ascii_isspace(tvb_get_guint8(tvb,counter))); counter++);
return (counter);
}
static gint megaco_tvb_skip_wsp_return(tvbuff_t* tvb, gint offset){
gint counter = offset;
gint end = 0;
for(counter = offset; counter > end &&
(g_ascii_isspace(tvb_get_guint8(tvb,counter))); counter--);
counter++;
return (counter);
}
static gint megaco_tvb_find_token(tvbuff_t* tvb, gint offset, gint maxlength){
gint counter = 0;
gint pos = offset;
guchar needle;
do {
pos = tvb_ws_mempbrk_pattern_guint8(tvb, pos + 1, maxlength, &pbrk_braces, &needle);
if(pos == -1)
return -1;
switch(needle){
case '{':
counter++;
break;
case '}':
counter--;
break;
default:
break;
}
} while (counter>0);
if(counter<0)
return -1;
else
{
pos = megaco_tvb_skip_wsp(tvb,pos+1);
return pos;
}
}
static void
megaco_fmt_content( gchar *result, guint32 context )
{
switch(context)
{
case CHOOSE_CONTEXT:
case ALL_CONTEXTS:
case NULL_CONTEXT:
(void) g_strlcpy(result, val_to_str_const(context, megaco_context_vals, "Unknown"), ITEM_LABEL_LENGTH);
break;
default:
snprintf( result, ITEM_LABEL_LENGTH, "%d", context);
}
}
void
proto_register_megaco(void)
{
static hf_register_info hf[] = {
{ &hf_megaco_audititem,
{ "Audit Item", "megaco.audititem", FT_STRING, BASE_NONE, NULL, 0x0,
"Identity of item to be audited", HFILL }},
{ &hf_megaco_audit_descriptor,
{ "Audit Descriptor", "megaco.audit", FT_NONE, BASE_NONE, NULL, 0x0,
"Audit Descriptor of the megaco Command", HFILL }},
#if 0
{ &hf_megaco_command_line,
{ "Command line", "megaco.command_line", FT_STRING, BASE_NONE, NULL, 0x0,
"Commands of this message", HFILL }},
#endif
{ &hf_megaco_command,
{ "Command", "megaco.command", FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_megaco_command_optional,
{ "Optional Command", "megaco.command_optional", FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_megaco_wildcard_response,
{ "Wildcarded response to a command", "megaco.wildcard_response", FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_megaco_Context,
{ "Context", "megaco.context", FT_UINT32, BASE_CUSTOM, CF_FUNC(megaco_fmt_content), 0x0,
"Context ID of this message", HFILL }},
{ &hf_megaco_digitmap_descriptor,
{ "DigitMap Descriptor", "megaco.digitmap", FT_STRING, BASE_NONE, NULL, 0x0,
"DigitMap Descriptor of the megaco Command", HFILL }},
{ &hf_megaco_error_descriptor,
{ "ERROR Descriptor", "megaco.error", FT_NONE, BASE_NONE, NULL, 0x0,
"Error Descriptor of the megaco Command", HFILL }},
{ &hf_megaco_error_code,
{ "ERROR Code", "megaco.error_code", FT_UINT32, BASE_DEC, VALS(MEGACO_error_code_vals), 0x0,
"Error Code of the megaco Command", HFILL }},
{ &hf_megaco_error_string,
{ "ERROR String", "megaco.error_string", FT_STRING, BASE_NONE, NULL, 0x0,
"Error String of the megaco Command", HFILL }},
{ &hf_megaco_Event_Buffer_Control,
{ "Event Buffer Control", "megaco.eventbuffercontrol", FT_STRING, BASE_NONE, NULL, 0x0,
"Event Buffer Control in Termination State Descriptor", HFILL }},
{ &hf_megaco_events_descriptor,
{ "Events Descriptor", "megaco.events", FT_NONE, BASE_NONE, NULL, 0x0,
"Events Descriptor of the megaco Command", HFILL }},
{ &hf_megaco_Local_descriptor,
{ "Local Descriptor", "megaco.localdescriptor", FT_NONE, BASE_NONE, NULL, 0x0,
"Local Descriptor in Media Descriptor", HFILL }},
{ &hf_megaco_LocalControl_descriptor,
{ "Local Control Descriptor", "megaco.localcontroldescriptor", FT_NONE, BASE_NONE, NULL, 0x0,
"Local Control Descriptor in Media Descriptor", HFILL }},
{ &hf_megaco_media_descriptor,
{ "Media Descriptor", "megaco.media", FT_NONE, BASE_NONE, NULL, 0x0,
"Media Descriptor of the megaco Command", HFILL }},
{ &hf_megaco_modem_descriptor,
{ "Modem Descriptor", "megaco.modem", FT_STRING, BASE_NONE, NULL, 0x0,
"Modem Descriptor of the megaco Command", HFILL }},
{ &hf_megaco_mode,
{ "Mode", "megaco.mode", FT_STRING, BASE_NONE, NULL, 0x0,
"Mode sendonly/receiveonly/inactive/loopback", HFILL }},
{ &hf_megaco_multiplex_descriptor,
{ "Multiplex Descriptor", "megaco.multiplex", FT_STRING, BASE_NONE, NULL, 0x0,
"Multiplex Descriptor of the megaco Command", HFILL }},
{ &hf_megaco_observedevents_descriptor,
{ "Observed Events Descriptor", "megaco.observedevents", FT_NONE, BASE_NONE, NULL, 0x0,
"Observed Events Descriptor of the megaco Command", HFILL }},
{ &hf_megaco_packages_descriptor,
{ "Packages Descriptor", "megaco.packagesdescriptor", FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_megaco_pkgdname,
{ "pkgdName", "megaco.pkgdname", FT_STRING, BASE_NONE, NULL, 0x0,
"PackageName SLASH ItemID", HFILL }},
{ &hf_megaco_Remote_descriptor,
{ "Remote Descriptor", "megaco.remotedescriptor", FT_NONE, BASE_NONE, NULL, 0x0,
"Remote Descriptor in Media Descriptor", HFILL }},
{ &hf_megaco_reserve_group,
{ "Reserve Group", "megaco.reservegroup", FT_STRING, BASE_NONE, NULL, 0x0,
"Reserve Group on or off", HFILL }},
{ &hf_megaco_h324_muxtbl_in,
{ "h324/muxtbl_in", "megaco.h324_muxtbl_in", FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_megaco_h324_muxtbl_out,
{ "h324/muxtbl_out", "megaco.h324_muxtbl_out", FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_megaco_ds_dscp,
{ "Differentiated Services Code Point", "megaco.ds_dscp", FT_UINT32, BASE_HEX|BASE_EXT_STRING, &dscp_vals_ext, 0x0,
NULL, HFILL }},
{ &hf_megaco_gm_saf,
{ "Remote Source Address Filtering", "megaco.gm_saf", FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_megaco_gm_sam,
{ "Remote Source Address Mask", "megaco.gm_sam", FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_megaco_gm_spf,
{ "Remote Source Port Filtering", "megaco.gm_spf", FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_megaco_gm_spr,
{ "Remote Source Port Range", "megaco.gm_spr", FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_megaco_gm_esas,
{ "Explicit Source Address Setting", "megaco.gm_esas", FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_megaco_tman_pol,
{ "Policing", "megaco.tman_pol", FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_megaco_gm_rsb,
{ "RTCP Allocation Specific Behaviour", "megaco.gm_rsb", FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_megaco_tman_sdr,
{ "Sustainable Data Rate", "megaco.tman_sdr", FT_INT32, BASE_DEC|BASE_UNIT_STRING, &units_byte_bytespsecond, 0x0,
NULL, HFILL }},
{ &hf_megaco_tman_mbs,
{ "Maximum Burst Rate", "megaco.tman_mbs", FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_megaco_tman_pdr,
{ "Peak Data Rate", "megaco.tman_pdr", FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_megaco_tman_dvt,
{ "Delay Variation Tolerance", "megaco.tman_dvt", FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_megaco_ipdc_realm,
{ "IP Realm Identifier", "megaco.ipdc_realm", FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_megaco_h324_h223capr,
{ "h324/h223capr", "megaco.h324_h223capr", FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_megaco_reserve_value,
{ "Reserve Value", "megaco.reservevalue", FT_STRING, BASE_NONE, NULL, 0x0,
"Reserve Value on or off", HFILL }},
{ &hf_megaco_requestid,
{ "RequestID", "megaco.requestid", FT_UINT32, BASE_DEC, NULL, 0x0,
"RequestID in Events or Observedevents Descriptor", HFILL }},
#if 0
{ &hf_megaco_servicechange_descriptor,
{ "Service Change Descriptor", "megaco.servicechange", FT_STRING, BASE_NONE, NULL, 0x0,
"Service Change Descriptor of the megaco Command", HFILL }},
#endif
{ &hf_megaco_Service_State,
{ "Service State", "megaco.servicestates", FT_STRING, BASE_NONE, NULL, 0x0,
"Service States in Termination State Descriptor", HFILL }},
{ &hf_megaco_signal_descriptor,
{ "Signal Descriptor", "megaco.signal", FT_NONE, BASE_NONE, NULL, 0x0,
"Signal Descriptor of the megaco Command", HFILL }},
{ &hf_megaco_statistics_descriptor,
{ "Statistics Descriptor", "megaco.statistics", FT_NONE, BASE_NONE, NULL, 0x0,
"Statistics Descriptor of the megaco Command", HFILL }},
{ &hf_megaco_streamid,
{ "StreamID", "megaco.streamid", FT_UINT32, BASE_DEC, NULL, 0x0,
"StreamID in the Media Descriptor", HFILL }},
{ &hf_megaco_termid,
{ "Termination ID", "megaco.termid", FT_STRING, BASE_NONE, NULL, 0x0,
"Termination ID of this Command", HFILL }},
{ &hf_megaco_TerminationState_descriptor,
{ "Termination State Descriptor", "megaco.terminationstate", FT_NONE, BASE_NONE, NULL, 0x0,
"Termination State Descriptor in Media Descriptor", HFILL }},
{ &hf_megaco_topology_descriptor,
{ "Topology Descriptor", "megaco.topology", FT_STRING, BASE_NONE, NULL, 0x0,
"Topology Descriptor of the megaco Command", HFILL }},
{ &hf_megaco_transaction,
{ "Transaction", "megaco.transaction", FT_STRING, BASE_NONE, NULL, 0x0,
"Message Originator", HFILL }},
{ &hf_megaco_transid,
{ "Transaction ID", "megaco.transid", FT_UINT32, BASE_DEC, NULL, 0x0,
"Transaction ID of this message", HFILL }},
{ &hf_megaco_mId,
{ "MediagatewayID", "megaco.mId", FT_STRING, BASE_NONE, NULL, 0x0,
"Mediagateway ID", HFILL }},
{ &hf_megaco_version,
{ "Version", "megaco.version", FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_megaco_start,
{ "Start token", "megaco.start_token", FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_megaco_h245,
{ "h245", "megaco.h245", FT_NONE, BASE_NONE, NULL, 0x0,
"Embedded H.245 message", HFILL }},
{ &hf_megaco_h223Capability,
{ "h223Capability", "megaco.h245.h223Capability", FT_NONE, BASE_NONE, NULL, 0,
"megaco.h245.H223Capability", HFILL }},
{ &hf_megaco_priority,
{ "Priority", "megaco.priority", FT_STRING, BASE_NONE, NULL, 0,
NULL, HFILL }},
GCP_HF_ARR_ELEMS("megaco",megaco_ctx_ids),
/* Add more fields here */
};
static gint *ett[] = {
&ett_megaco,
&ett_megaco_message,
&ett_megaco_message_body,
&ett_megaco_context,
&ett_megaco_command_line,
&ett_megaco_descriptors,
&ett_megaco_raw_text,
&ett_megaco_error_descriptor,
&ett_megaco_mediadescriptor,
&ett_megaco_TerminationState,
&ett_megaco_Remotedescriptor,
&ett_megaco_Localdescriptor,
&ett_megaco_LocalControldescriptor,
&ett_megaco_auditdescriptor,
&ett_megaco_eventsdescriptor,
&ett_megaco_statisticsdescriptor,
&ett_megaco_observedeventsdescriptor,
&ett_megaco_observedevent,
&ett_megaco_packagesdescriptor,
&ett_megaco_requestedevent,
&ett_megaco_signalsdescriptor,
&ett_megaco_requestedsignal,
&ett_megaco_h245,
GCP_ETT_ARR_ELEMS(megaco_ctx_ids),
};
static ei_register_info ei[] = {
{ &ei_megaco_errored_command, { "megaco.errored_command", PI_RESPONSE_CODE, PI_WARN, "Errored Command", EXPFILL }},
{ &ei_megaco_parse_error, { "megaco.parse_error", PI_MALFORMED, PI_ERROR, "Parse error", EXPFILL }},
{ &ei_megaco_error_descriptor_transaction_list, { "megaco.error_descriptor_transaction_list.invalid", PI_MALFORMED, PI_ERROR, "Sorry, can't understand errorDescriptor / transactionList", EXPFILL }},
{ &ei_megaco_audit_descriptor, { "megaco.audit.malformed", PI_MALFORMED, PI_ERROR, "Badly constructed audit descriptor (no { )", EXPFILL }},
{ &ei_megaco_signal_descriptor, { "megaco.signal_descriptor.empty", PI_PROTOCOL, PI_NOTE, "Empty Signal Descriptor", EXPFILL }},
{ &ei_megaco_no_command, { "megaco.no_command", PI_PROTOCOL, PI_WARN, "No Command detectable", EXPFILL }},
{ &ei_megaco_no_descriptor, { "megaco.no_descriptor", PI_PROTOCOL, PI_WARN, "No Descriptor detectable", EXPFILL }},
{ &ei_megaco_reason_invalid, { "megaco.change_reason.invalid", PI_MALFORMED, PI_ERROR, "Invalid Service Change Reason", EXPFILL }},
{ &ei_megaco_error_code_invalid,{ "megaco.error_code.invalid", PI_MALFORMED, PI_ERROR, "Invalid error code", EXPFILL } },
{ &ei_megaco_invalid_sdr, { "megaco.sdr.invalid", PI_MALFORMED, PI_ERROR, "Invalid Sustainable Data Rate", EXPFILL }}
};
module_t *megaco_module;
expert_module_t* expert_megaco;
proto_megaco = proto_register_protocol("MEGACO", "MEGACO", "megaco");
megaco_text_handle = register_dissector("megaco", dissect_megaco_text, proto_megaco);
proto_register_field_array(proto_megaco, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
expert_megaco = expert_register_protocol(proto_megaco);
expert_register_field_array(expert_megaco, ei, array_length(ei));
/* Register our configuration options, particularly our ports */
megaco_module = prefs_register_protocol(proto_megaco, proto_reg_handoff_megaco);
prefs_register_uint_preference(megaco_module, "sctp.txt_port",
"MEGACO Text SCTP Port",
"Set the SCTP port for MEGACO text messages",
10, &global_megaco_txt_sctp_port);
#if 0
prefs_register_uint_preference(megaco_module, "sctp.bin_port",
"MEGACO Binary SCTP Port",
"Set the SCTP port for MEGACO binary messages",
10, &global_megaco_bin_sctp_port);
prefs_register_uint_preference(megaco_module, "tcp.bin_port",
"MEGACO Binary TCP Port",
"Set the TCP port for MEGACO binary messages",
10, &global_megaco_bin_tcp_port);
prefs_register_uint_preference(megaco_module, "udp.bin_port",
"MEGACO Binary UDP Port",
"Set the UDP port for MEGACO binary messages",
10, &global_megaco_bin_udp_port);
#endif
prefs_register_bool_preference(megaco_module, "display_raw_text",
"Display raw text for MEGACO message",
"Specifies that the raw text of the "
"MEGACO message should be displayed "
"instead of (or in addition to) the "
"dissection tree",
&global_megaco_raw_text);
prefs_register_bool_preference(megaco_module, "display_dissect_tree",
"Display tree dissection for MEGACO message",
"Specifies that the dissection tree of the "
"MEGACO message should be displayed "
"instead of (or in addition to) the "
"raw text",
&global_megaco_dissect_tree);
prefs_register_bool_preference(megaco_module, "ctx_info",
"Track Context",
"Maintain relationships between transactions and contexts "
"and display an extra tree showing context data",
&keep_persistent_data);
megaco_tap = register_tap("megaco");
/* compile patterns */
ws_mempbrk_compile(&pbrk_whitespace, " \t\r\n");
ws_mempbrk_compile(&pbrk_braces, "{}");
register_rtd_table(proto_megaco, NULL, 1, NUM_TIMESTATS, megaco_message_type, megacostat_packet, megacostat_filtercheck);
}
/* Register all the bits needed with the filtering engine */
/* The registration hand-off routine */
void
proto_reg_handoff_megaco(void)
{
static gboolean megaco_prefs_initialized = FALSE;
static dissector_handle_t megaco_text_tcp_handle;
/*
* Variables to allow for proper deletion of dissector registration when
* the user changes port from the gui.
*/
static guint txt_sctp_port;
#if 0
static guint bin_sctp_port;
static guint bin_tcp_port;
static guint bin_udp_port;
#endif
if (!megaco_prefs_initialized) {
sdp_handle = find_dissector_add_dependency("sdp", proto_megaco);
h245_handle = find_dissector_add_dependency("h245dg", proto_megaco);
h248_handle = find_dissector_add_dependency("h248", proto_megaco);
h248_otp_handle = find_dissector_add_dependency("h248_otp", proto_megaco);
data_handle = find_dissector("data");
megaco_text_tcp_handle = create_dissector_handle(dissect_megaco_text_tcp, proto_megaco);
dissector_add_uint_with_preference("tcp.port", PORT_MEGACO_TXT, megaco_text_tcp_handle);
dissector_add_uint_with_preference("udp.port", PORT_MEGACO_TXT, megaco_text_handle);
dissector_add_uint("sctp.ppi", H248_PAYLOAD_PROTOCOL_ID, megaco_text_handle);
megaco_prefs_initialized = TRUE;
} else {
dissector_delete_uint("sctp.port", txt_sctp_port, megaco_text_handle);
}
/* Set our port number for future use */
txt_sctp_port = global_megaco_txt_sctp_port;
dissector_add_uint("sctp.port", global_megaco_txt_sctp_port, megaco_text_handle);
exported_pdu_tap = find_tap_id(EXPORT_PDU_TAP_NAME_LAYER_7);
sip_hide_generated_call_ids = prefs_find_preference(prefs_find_module("sip"), "hide_generated_call_id");
}
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/