494adf93d5b6063dfc26c595fc6d4bd22c9a3e3a
[metze/wireshark/wip.git] / epan / dissectors / packet-megaco.c
1 /* packet-megaco.c
2 * Routines for megaco packet disassembly
3 * RFC 3015
4 *
5 * Christian Falckenberg, 2002/10/17
6 * Copyright (c) 2002 by Christian Falckenberg
7 *                       <christian.falckenberg@nortelnetworks.com>
8 *
9 * Christoph Wiest,      2003/06/28
10 * Modified 2003 by      Christoph Wiest
11 *                       <ch.wiest@tesionmail.de>
12 * Modified 2004 by      Anders Broman
13 *                       <anders.broman@ericsson.com>
14 * To handle TPKT headers if over TCP
15 * Modified 2005 by      Karl Knoebl
16 *                       <karl.knoebl@siemens.com>
17 *   provide info to COL_INFO and some "prettification"
18 *
19 * Copyright (c) 2006 Anders Broman <anders.broman@ericsson.com>
20 *
21 * Wireshark - Network traffic analyzer
22 * By Gerald Combs <gerald@wireshark.org>
23 * Copyright 1999 Gerald Combs
24 *
25 * This program is free software; you can redistribute it and/or
26 * modify it under the terms of the GNU General Public License
27 * as published by the Free Software Foundation; either version 2
28 * of the License, or (at your option) any later version.
29 *
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
33 * GNU General Public License for more details.
34 *
35 * You should have received a copy of the GNU General Public License
36 * along with this program; if not, write to the Free Software
37 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
38 */
39
40
41 #include "config.h"
42
43 #include <stdlib.h>
44
45 #include <epan/packet.h>
46 #include <epan/exceptions.h>
47 #include <epan/tap.h>
48 #include <epan/rtd_table.h>
49 #include <epan/prefs.h>
50 #include <epan/prefs-int.h>
51 #include <epan/exported_pdu.h>
52 #include <epan/asn1.h>
53 #include <epan/sctpppids.h>
54 #include <wsutil/strtoi.h>
55 #include "packet-ber.h"
56 #include "packet-tpkt.h"
57 #include "packet-h245.h"
58 #include "packet-h248.h"
59 #include "packet-ip.h"
60
61 void proto_register_megaco(void);
62 void proto_reg_handoff_megaco(void);
63
64 #define PORT_MEGACO_TXT 2944
65 #define PORT_MEGACO_BIN 2945
66
67 /* Define the megaco proto */
68 static int proto_megaco         = -1;
69
70 /* Define headers for megaco */
71 static int hf_megaco_start          = -1;
72 static int hf_megaco_version        = -1;
73 static int hf_megaco_transaction    = -1;
74 static int hf_megaco_transid        = -1;
75 static int hf_megaco_Context        = -1;
76 /* static int hf_megaco_command_line   = -1; */
77 static int hf_megaco_command        = -1;
78 static int hf_megaco_command_optional = -1;
79 static int hf_megaco_wildcard_response = -1;
80 static int hf_megaco_termid         = -1;
81
82
83
84 /* Define headers in subtree for megaco */
85 static int hf_megaco_modem_descriptor           = -1;
86 static int hf_megaco_multiplex_descriptor       = -1;
87 static int hf_megaco_media_descriptor           = -1;
88 static int hf_megaco_Local_descriptor           = -1;
89 static int hf_megaco_events_descriptor          = -1;
90 static int hf_megaco_signal_descriptor          = -1;
91 static int hf_megaco_audit_descriptor           = -1;
92 /* static int hf_megaco_servicechange_descriptor   = -1; */
93 static int hf_megaco_digitmap_descriptor        = -1;
94 static int hf_megaco_statistics_descriptor      = -1;
95 static int hf_megaco_observedevents_descriptor  = -1;
96 static int hf_megaco_topology_descriptor        = -1;
97 static int hf_megaco_error_descriptor           = -1;
98 static int hf_megaco_error_code                 = -1;
99 static int hf_megaco_error_string               = -1;
100 static int hf_megaco_TerminationState_descriptor= -1;
101 /* static int hf_megaco_Remote_descriptor          = -1; */
102 static int hf_megaco_LocalControl_descriptor    = -1;
103 static int hf_megaco_packages_descriptor        = -1;
104 static int hf_megaco_Service_State              = -1;
105 static int hf_megaco_Event_Buffer_Control       = -1;
106 static int hf_megaco_mode                       = -1;
107 static int hf_megaco_reserve_group              = -1;
108 static int hf_megaco_h324_muxtbl_in             = -1;
109 static int hf_megaco_h324_muxtbl_out            = -1;
110 static int hf_megaco_ds_dscp                    = -1;
111 static int hf_megaco_gm_saf                     = -1;
112 static int hf_megaco_gm_sam                     = -1;
113 static int hf_megaco_gm_spf                     = -1;
114 static int hf_megaco_gm_spr                     = -1;
115 static int hf_megaco_gm_esas                    = -1;
116 static int hf_megaco_tman_pol                   = -1;
117 static int hf_megaco_gm_rsb                     = -1;
118 static int hf_megaco_tman_sdr                   = -1;
119 static int hf_megaco_tman_mbs                   = -1;
120 static int hf_megaco_tman_pdr                   = -1;
121 static int hf_megaco_tman_dvt                   = -1;
122 static int hf_megaco_ipdc_realm                 = -1;
123 static int hf_megaco_h324_h223capr              = -1;
124 static int hf_megaco_reserve_value              = -1;
125 static int hf_megaco_streamid                   = -1;
126 static int hf_megaco_requestid                  = -1;
127 static int hf_megaco_pkgdname                   = -1;
128 static int hf_megaco_mId                        = -1;
129 static int hf_megaco_h245                       = -1;
130 static int hf_megaco_h223Capability             = -1;
131 static int hf_megaco_audititem                  = -1;
132
133 /* Define the trees for megaco */
134 static int ett_megaco                           = -1;
135 static int ett_megaco_message                   = -1;
136 static int ett_megaco_message_body              = -1;
137 static int ett_megaco_context                   = -1;
138 static int ett_megaco_command_line              = -1;
139 static int ett_megaco_mediadescriptor           = -1;
140 static int ett_megaco_descriptors               = -1;
141 static int ett_megaco_raw_text                  = -1;
142 static int ett_megaco_error_descriptor          = -1;
143 static int ett_megaco_TerminationState          = -1;
144 static int ett_megaco_Localdescriptor           = -1;
145 static int ett_megaco_Remotedescriptor          = -1;
146 static int ett_megaco_LocalControldescriptor    = -1;
147 static int ett_megaco_auditdescriptor           = -1;
148 static int ett_megaco_eventsdescriptor          = -1;
149 static int ett_megaco_statisticsdescriptor      = -1;
150 static int ett_megaco_observedeventsdescriptor  = -1;
151 static int ett_megaco_observedevent             = -1;
152 static int ett_megaco_packagesdescriptor        = -1;
153 static int ett_megaco_requestedevent            = -1;
154 static int ett_megaco_signalsdescriptor         = -1;
155 static int ett_megaco_requestedsignal           = -1;
156 static int ett_megaco_h245                      = -1;
157
158 static gcp_hf_ett_t megaco_ctx_ids = {{-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1}};
159
160 static expert_field ei_megaco_errored_command = EI_INIT;
161 static expert_field ei_megaco_no_command = EI_INIT;
162 static expert_field ei_megaco_no_descriptor = EI_INIT;
163 static expert_field ei_megaco_error_descriptor_transaction_list = EI_INIT;
164 static expert_field ei_megaco_parse_error = EI_INIT;
165 static expert_field ei_megaco_audit_descriptor = EI_INIT;
166 static expert_field ei_megaco_signal_descriptor = EI_INIT;
167 static expert_field ei_megaco_reason_invalid = EI_INIT;
168 static expert_field ei_megaco_error_code_invalid = EI_INIT;
169
170 static dissector_handle_t megaco_text_handle;
171
172 static int megaco_tap = -1;
173 static gint exported_pdu_tap = -1;
174
175
176 /* patterns used for tvb_ws_mempbrk_pattern_guint8 */
177 static ws_mempbrk_pattern pbrk_whitespace;
178 static ws_mempbrk_pattern pbrk_braces;
179
180
181 /*
182 * Here are the global variables associated with
183 * the various user definable characteristics of the dissection
184 *
185 * MEGACO has two kinds of message formats: text and binary
186 *
187 * global_megaco_raw_text determines whether we are going to display
188 * the raw text of the megaco message, much like the HTTP dissector does.
189 *
190 * global_megaco_dissect_tree determines whether we are going to display
191 * a detailed tree that expresses a somewhat more semantically meaningful
192 * decode.
193 */
194 static guint global_megaco_txt_sctp_port = PORT_MEGACO_TXT;
195 #if 0
196 static guint global_megaco_bin_sctp_port = PORT_MEGACO_BIN;
197 static guint global_megaco_bin_tcp_port = PORT_MEGACO_BIN;
198 static guint global_megaco_bin_udp_port = PORT_MEGACO_BIN;
199 #endif
200 static gboolean global_megaco_raw_text = TRUE;
201 static gboolean global_megaco_dissect_tree = TRUE;
202
203 static const value_string megaco_context_vals[] = {
204    { CHOOSE_CONTEXT,       "Choose one"     },
205    { ALL_CONTEXTS,         "All"            },
206    { NULL_CONTEXT,         "NULL"           },
207
208    { 0,                    NULL }
209 };
210
211 /* Some basic utility functions that are specific to this dissector */
212 static gint megaco_tvb_skip_wsp(tvbuff_t *tvb, gint offset);
213 static gint megaco_tvb_skip_wsp_return(tvbuff_t *tvb, gint offset);
214
215 #define NUM_TIMESTATS 12
216
217 static const value_string megaco_message_type[] = {
218     {  0, "ADD "},
219     {  1, "MOVE"},
220     {  2, "MDFY"},
221     {  3, "SUBT"},
222     {  4, "AUCP"},
223     {  5, "AUVL"},
224     {  6, "NTFY"},
225     {  7, "SVCC"},
226     {  8, "TOPO"},
227     {  9, "NONE"},
228     { 10, "ALL "},
229     {  0, NULL}
230 };
231
232 #define GCP_CMD_REPLY_CASE \
233     case GCP_CMD_ADD_REPLY: \
234     case GCP_CMD_MOVE_REPLY: \
235     case GCP_CMD_MOD_REPLY: \
236     case GCP_CMD_SUB_REPLY: \
237     case GCP_CMD_AUDITCAP_REPLY: \
238     case GCP_CMD_AUDITVAL_REPLY: \
239     case GCP_CMD_NOTIFY_REPLY: \
240     case GCP_CMD_SVCCHG_REPLY: \
241     case GCP_CMD_TOPOLOGY_REPLY: \
242     case GCP_CMD_REPLY:
243
244 #define GCP_CMD_REQ_CASE \
245     case GCP_CMD_ADD_REQ: \
246     case GCP_CMD_MOVE_REQ: \
247     case GCP_CMD_MOD_REQ: \
248     case GCP_CMD_SUB_REQ: \
249     case GCP_CMD_AUDITCAP_REQ: \
250     case GCP_CMD_AUDITVAL_REQ: \
251     case GCP_CMD_NOTIFY_REQ: \
252     case GCP_CMD_SVCCHG_REQ: \
253     case GCP_CMD_TOPOLOGY_REQ: \
254     case GCP_CMD_CTX_ATTR_AUDIT_REQ: \
255     case GCP_CMD_OTHER_REQ:
256
257 static gboolean
258 megacostat_is_duplicate_reply(const gcp_cmd_t* cmd)
259 {
260     switch (cmd->type) {
261
262     GCP_CMD_REPLY_CASE
263         {
264             gcp_cmd_msg_t *cmd_msg;
265             /* cycle through commands to find same command in the transaction */
266             for (cmd_msg = cmd->trx->cmds;
267                 (cmd_msg != NULL) && (cmd_msg->cmd->msg->framenum != cmd->msg->framenum);
268                 cmd_msg = cmd_msg->next) {
269                 if (cmd_msg->cmd->type == cmd->type)
270                     return TRUE;
271             }
272
273             return FALSE;
274         }
275         break;
276     default:
277         return FALSE;
278         break;
279     }
280 }
281
282 static gboolean
283 megacostat_had_request(const gcp_cmd_t* cmd)
284 {
285     switch (cmd->type) {
286
287     GCP_CMD_REPLY_CASE
288         {
289             gcp_cmd_msg_t *cmd_msg;
290             /* cycle through commands to find a request in the transaction */
291             for (cmd_msg = cmd->trx->cmds;
292                     (cmd_msg != NULL) && (cmd_msg->cmd->msg->framenum != cmd->msg->framenum);
293                     cmd_msg = cmd_msg->next) {
294
295                     switch (cmd_msg->cmd->type) {
296
297                     GCP_CMD_REQ_CASE
298                         return TRUE;
299                         break;
300                     default:
301                         return FALSE;
302                         break;
303                     }
304             }
305
306             return FALSE;
307         }
308         break;
309     default:
310         return FALSE;
311         break;
312     }
313 }
314
315 static void
316 megacostat_filtercheck(const char *opt_arg _U_, const char **filter _U_, char** err)
317 {
318     pref_t *megaco_ctx_track, *h248_ctx_track;
319
320     megaco_ctx_track = prefs_find_preference(prefs_find_module("megaco"), "ctx_info");
321     h248_ctx_track = prefs_find_preference(prefs_find_module("h248"), "ctx_info");
322
323     if (!megaco_ctx_track || !h248_ctx_track) {
324         /* No such preferences */
325         return;
326     }
327
328     if (!prefs_get_bool_value(megaco_ctx_track, pref_current) || !prefs_get_bool_value(h248_ctx_track, pref_current)) {
329         *err = g_strdup_printf("Track Context option at Protocols -> MEGACO and Protocols -> H248 preferences\n"
330                                 "has to be set to true to enable measurement of service response times.\n");
331     }
332 }
333
334 static int
335 megacostat_packet(void *pms, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pmi)
336 {
337     rtd_data_t* rtd_data = (rtd_data_t*)pms;
338     rtd_stat_table* ms = &rtd_data->stat_table;
339     const gcp_cmd_t *mi=(const gcp_cmd_t*)pmi;
340     nstime_t delta;
341     int ret = 0;
342
343     switch (mi->type) {
344
345     GCP_CMD_REQ_CASE
346         if(!mi->trx->initial) {
347             /* Track Context is probably disabled, we cannot
348                 * measure service response time */
349             return 0;
350         }
351
352         else if(mi->trx->initial->framenum != mi->msg->framenum){
353             /* Duplicate is ignored */
354             ms->time_stats[0].req_dup_num++;
355         }
356         else {
357             ms->time_stats[0].open_req_num++;
358         }
359         break;
360
361     GCP_CMD_REPLY_CASE
362         if(megacostat_is_duplicate_reply(mi)){
363             /* Duplicate is ignored */
364             ms->time_stats[0].rsp_dup_num++;
365         }
366         else if (!megacostat_had_request(mi)) {
367             /* no request was seen */
368             ms->time_stats[0].disc_rsp_num++;
369         }
370         else {
371             ms->time_stats[0].open_req_num--;
372             /* calculate time delta between request and response */
373             nstime_delta(&delta, &pinfo->abs_ts, &mi->trx->initial->frametime);
374
375             switch(mi->type) {
376
377             case GCP_CMD_ADD_REPLY:
378                 time_stat_update(&(ms->time_stats[0].rtd[0]),&delta, pinfo);
379                 break;
380             case GCP_CMD_MOVE_REPLY:
381                 time_stat_update(&(ms->time_stats[0].rtd[1]),&delta, pinfo);
382                 break;
383             case GCP_CMD_MOD_REPLY:
384                 time_stat_update(&(ms->time_stats[0].rtd[2]),&delta, pinfo);
385                 break;
386             case GCP_CMD_SUB_REPLY:
387                 time_stat_update(&(ms->time_stats[0].rtd[3]),&delta, pinfo);
388                 break;
389             case GCP_CMD_AUDITCAP_REPLY:
390                 time_stat_update(&(ms->time_stats[0].rtd[4]),&delta, pinfo);
391                 break;
392             case GCP_CMD_AUDITVAL_REPLY:
393                 time_stat_update(&(ms->time_stats[0].rtd[5]),&delta, pinfo);
394                 break;
395             case GCP_CMD_NOTIFY_REPLY:
396                 time_stat_update(&(ms->time_stats[0].rtd[6]),&delta, pinfo);
397                 break;
398             case GCP_CMD_SVCCHG_REPLY:
399                 time_stat_update(&(ms->time_stats[0].rtd[7]),&delta, pinfo);
400                 break;
401             case GCP_CMD_TOPOLOGY_REPLY:
402                 time_stat_update(&(ms->time_stats[0].rtd[8]),&delta, pinfo);
403                 break;
404             case GCP_CMD_REPLY:
405                 time_stat_update(&(ms->time_stats[0].rtd[9]),&delta, pinfo);
406                 break;
407             default:
408                 time_stat_update(&(ms->time_stats[0].rtd[11]),&delta, pinfo);
409             }
410
411             time_stat_update(&(ms->time_stats[0].rtd[10]),&delta, pinfo);
412             ret = 1;
413         }
414         break;
415
416     default:
417         break;
418     }
419
420     return ret;
421 }
422
423 /* Call the export PDU tap with relevant data */
424 static void
425 export_megaco_pdu(packet_info *pinfo, tvbuff_t *tvb)
426 {
427     exp_pdu_data_t *exp_pdu_data = export_pdu_create_common_tags(pinfo, "megaco", EXP_PDU_TAG_PROTO_NAME);
428
429     exp_pdu_data->tvb_captured_length = tvb_captured_length(tvb);
430     exp_pdu_data->tvb_reported_length = tvb_reported_length(tvb);
431     exp_pdu_data->pdu_tvb = tvb;
432
433     tap_queue_packet(exported_pdu_tap, pinfo, exp_pdu_data);
434
435 }
436
437 /*
438 * The various functions that either dissect some
439 * subpart of MEGACO.  These aren't really proto dissectors but they
440 * are written in the same style.
441 *
442 */
443 static void
444 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);
445 static void
446 dissect_megaco_digitmapdescriptor(tvbuff_t *tvb, proto_tree *tree, gint tvb_RBRKT, gint tvb_previous_offset);
447 static void
448 dissect_megaco_topologydescriptor(tvbuff_t *tvb, proto_tree *tree, gint tvb_RBRKT, gint tvb_previous_offset);
449 static void
450 dissect_megaco_errordescriptor(tvbuff_t *tvb, packet_info* pinfo, proto_tree *tree, gint tvb_RBRKT, gint tvb_previous_offset);
451 static void
452 dissect_megaco_TerminationStatedescriptor(tvbuff_t *tvb, proto_tree *tree, gint tvb_next_offset, gint tvb_current_offset);
453 static void
454 dissect_megaco_Localdescriptor(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, gint tvb_next_offset, gint tvb_current_offset);
455 static void
456 dissect_megaco_LocalControldescriptor(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, gint tvb_next_offset, gint tvb_current_offset, proto_tree *top_tree);
457 static void
458 dissect_megaco_Packagesdescriptor(tvbuff_t *tvb, proto_tree *tree, gint tvb_next_offset, gint tvb_current_offset);
459 static void
460 tvb_raw_text_add(tvbuff_t *tvb, proto_tree *tree);
461 static int
462 dissect_megaco_text(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data);
463 static gint
464 megaco_tvb_find_token(tvbuff_t *tvb, gint offset, gint maxlength);
465 static dissector_handle_t data_handle;
466 static dissector_handle_t sdp_handle;
467 static dissector_handle_t h245_handle;
468 static dissector_handle_t h248_handle;
469 static dissector_handle_t h248_otp_handle;
470
471 static gboolean keep_persistent_data = FALSE;
472
473 /*
474  * dissect_megaco_text over TCP, there will be a TPKT header there
475  *
476  */
477 static int dissect_megaco_text_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
478 {
479     int lv_tpkt_len;
480
481     /* This code is copied from the Q.931 dissector, some parts skipped.
482      * Check whether this looks like a TPKT-encapsulated
483      * MEGACO packet.
484      *
485      * The minimum length of a MEGACO message is 6?:
486      * Re-assembly ?
487      */
488     lv_tpkt_len = is_tpkt(tvb, 6);
489     if (lv_tpkt_len == -1) {
490         /*
491          * It's not a TPKT packet;
492          * Is in MEGACO ?
493          */
494         dissect_megaco_text(tvb, pinfo, tree, data);
495     }
496     dissect_tpkt_encap(tvb, pinfo, tree, TRUE,
497         megaco_text_handle);
498
499     return tvb_captured_length(tvb);
500 }
501
502 #define ERRORTOKEN          1
503 #define TRANSTOKEN          2
504 #define REPLYTOKEN          3
505 #define PENDINGTOKEN        4
506 #define RESPONSEACKTOKEN    5
507
508 typedef struct {
509     const char *name;
510     const char *compact_name;
511 } megaco_tokens_t;
512
513 static const megaco_tokens_t megaco_messageBody_names[] = {
514     { "Unknown-token",              NULL }, /* 0 Pad so that the real headers start at index 1 */
515     { "Error",                      "ER" }, /* 1 */
516     { "Transaction",                "T" },  /* 2 */
517     { "Reply",                      "P" },  /* 3 */
518     { "Pending",                    "PN" }, /* 4 */
519     { "TransactionResponseAck",     "K" },  /* 5 */
520 };
521
522 /* Returns index of megaco_tokens_t */
523 static gint find_megaco_messageBody_names(tvbuff_t *tvb, int offset, guint header_len)
524 {
525     guint i;
526
527     for (i = 1; i < array_length(megaco_messageBody_names); i++) {
528         if (header_len == strlen(megaco_messageBody_names[i].name) &&
529             tvb_strncaseeql(tvb, offset, megaco_messageBody_names[i].name, header_len) == 0)
530             return i;
531         if (megaco_messageBody_names[i].compact_name != NULL &&
532             header_len == strlen(megaco_messageBody_names[i].compact_name) &&
533             tvb_strncaseeql(tvb, offset, megaco_messageBody_names[i].compact_name, header_len) == 0)
534             return i;
535     }
536
537     return -1;
538 }
539
540 static proto_item *
541 megaco_tree_add_string(proto_tree *tree, int hfindex, tvbuff_t *tvb,
542              gint start, gint length, const char *value)
543 {
544     proto_item *pi;
545
546     pi = proto_tree_add_string(tree, hfindex, tvb, start, length, value);
547     if (!global_megaco_dissect_tree) {
548         PROTO_ITEM_SET_HIDDEN(pi);
549     }
550
551     return(pi);
552 }
553
554 static proto_item *
555 my_proto_tree_add_uint(proto_tree *tree, int hfindex, tvbuff_t *tvb,
556              gint start, gint length, guint32 value)
557 {
558     proto_item *pi;
559
560     pi = proto_tree_add_uint(tree, hfindex, tvb, start, 1, value);
561     /* String length may be longer than FT_UINT will allow */
562     proto_item_set_len(pi, length);
563
564     if (!global_megaco_dissect_tree) {
565         PROTO_ITEM_SET_HIDDEN(pi);
566     }
567
568     return(pi);
569 }
570
571 /*
572  * dissect_megaco_text - The dissector for the MEGACO Protocol, using
573  * text encoding.
574  */
575 static int
576 dissect_megaco_text(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
577 {
578     gint        tvb_len, len;
579     gint        tvb_offset,tvb_current_offset,tvb_previous_offset,tvb_next_offset,tokenlen;
580     gint        context_offset, context_length, save_offset, save_length;
581     gint        tvb_command_start_offset, tvb_command_end_offset;
582     gint        tvb_descriptors_start_offset, tvb_descriptors_end_offset;
583     gint        tvb_transaction_end_offset;
584     proto_tree  *megaco_tree, *message_body_tree, *megaco_tree_command_line, *ti, *sub_ti;
585
586     guint8      word[15];
587     guint8      TermID[30];
588     guint8      tempchar;
589     gint        tvb_RBRKT, tvb_LBRKT,  RBRKT_counter, LBRKT_counter;
590     guint       token_index=0;
591     guint32     dword;
592     guchar      needle;
593
594     gcp_msg_t      *msg       = NULL;
595     gcp_trx_t      *trx       = NULL;
596     gcp_ctx_t      *ctx       = NULL;
597     gcp_cmd_t      *cmd       = NULL;
598     gcp_term_t     *term      = NULL;
599     gcp_trx_type_t  trx_type  = GCP_TRX_NONE;
600     guint32         trx_id    = 0, pending_id;
601     guint32         ctx_id    = 0;
602     gcp_cmd_type_t  cmd_type  = GCP_CMD_NONE;
603     gcp_wildcard_t  wild_term = GCP_WILDCARD_NONE;
604     gboolean        short_form;
605
606     /* Initialize variables */
607     tvb_len                     = tvb_reported_length(tvb);
608     megaco_tree                 = NULL;
609     ti                          = NULL;
610     tvb_offset                  = 0;
611     RBRKT_counter               = 0;
612     LBRKT_counter               = 0;
613
614     /* Check if H.248 in otp(Erlang) internal format
615      * XXX Needs improvement?
616      * Ref:
617      * http://www.erlang.org/doc/apps/megaco/part_frame.html
618      * 4.1 Internal form of messages
619      * 4.2 The different encodings
620      */
621     dword = tvb_get_ntoh24(tvb,0);
622     if ((dword == 0x836803)&&(h248_otp_handle)){
623         call_dissector(h248_otp_handle, tvb, pinfo, tree);
624         return tvb_captured_length(tvb);
625     }
626
627     msg = gcp_msg(pinfo, tvb_raw_offset(tvb), keep_persistent_data);
628
629     /*
630      * Check to see whether we're really dealing with MEGACO by looking
631      * for the "MEGACO" string or a "!".This needs to be improved when supporting
632      * binary encodings. Bugfix add skipping of leading spaces.
633      */
634     tvb_offset = megaco_tvb_skip_wsp(tvb, tvb_offset);
635
636     /* Quick fix for MEGACO not following the RFC, hopefully not breaking any thing
637      * Turned out to be TPKT in case of TCP, added some code to handle that.
638      *
639      * tvb_offset = tvb_find_guint8(tvb, tvb_offset, 5, 'M');
640      */
641     if(!tvb_get_nstringz0(tvb,tvb_offset,sizeof(word),word)) return tvb_captured_length(tvb);
642
643     /* Quick fix for MEGACO packet with Authentication Header,
644      * marked as "AU" or "Authentication".
645      */
646     if ((g_ascii_strncasecmp(word, "Authentication", 14) == 0) ||
647         (g_ascii_strncasecmp(word, "AU", 2) == 0)) {
648         gint counter;
649         guint8 next;
650
651         /* move offset to end of auth header (EOL or WSP) */
652         for ( counter = tvb_offset; counter < tvb_len; counter++ ) {
653             needle = tvb_get_guint8(tvb, counter);
654             if (needle == ' ' || needle == '\r' || needle == '\n') {
655                 next = tvb_get_guint8(tvb, counter+1);
656                 if (next == ' ' || next == '\r' || next == '\n') {
657                     continue;
658                 }
659                 tvb_offset = counter + 1;
660                 break;
661             }
662         }
663     }
664
665     short_form = (tvb_get_guint8(tvb, tvb_offset ) == '!');
666
667     if (g_ascii_strncasecmp(word, "MEGACO", 6) != 0 && !short_form){
668         gint8 ber_class;
669         gboolean pc;
670         gint32 tag;
671         dissector_handle_t handle = data_handle;
672
673         get_ber_identifier(tvb, 0, &ber_class, &pc, &tag);
674
675         if (ber_class == BER_CLASS_UNI && pc && tag == BER_UNI_TAG_SEQUENCE ) {
676             handle = h248_handle;
677         }
678
679         call_dissector(handle,tvb,pinfo,tree);
680         return tvb_captured_length(tvb);
681     }
682
683
684     /* Display MEGACO in protocol column */
685     col_set_str(pinfo->cinfo, COL_PROTOCOL, "MEGACO");
686
687     /* Report this packet to the tap */
688     if (!pinfo->flags.in_error_pkt) {
689         if (have_tap_listener(exported_pdu_tap)) {
690             export_megaco_pdu(pinfo, tvb);
691         }
692     }
693
694     /* Build the info tree if we've been given a root */
695     /* Create megaco subtree */
696     ti = proto_tree_add_item(tree,proto_megaco,tvb, 0, -1, ENC_NA);
697     megaco_tree = proto_item_add_subtree(ti, ett_megaco);
698
699     /*  Format of 'message' is = MegacopToken SLASH Version SEP mId SEP messageBody */
700     /*  MegacopToken = "MEGACO" or "!"                      */
701     /*  According to H248.1-200205 Annex B Text encoding ( protocol version 2 )     */
702
703     /* Find version */
704     tvb_previous_offset = tvb_find_guint8(tvb, 0,
705         tvb_len, '/');
706     if (tvb_previous_offset == -1) {
707         expert_add_info_format(pinfo, ti, &ei_megaco_parse_error,
708             "Sorry, no \"/\" in the MEGACO header, I can't parse this packet");
709         return tvb_captured_length(tvb);
710     }
711
712     megaco_tree_add_string(megaco_tree, hf_megaco_start, tvb, 0, tvb_previous_offset+1,
713                     tvb_get_string_enc(wmem_packet_scope(), tvb, 0, tvb_previous_offset, ENC_UTF_8|ENC_NA));
714
715     /* skip / */
716     tvb_previous_offset++;
717
718     /* assume at least one digit in version */
719     tvb_current_offset = tvb_previous_offset + 1;
720
721     if (g_ascii_isdigit(tvb_get_guint8(tvb, tvb_current_offset))) {
722         /* 2-digit version */
723         tvb_current_offset++;
724     }
725
726     megaco_tree_add_string(megaco_tree, hf_megaco_version, tvb, tvb_previous_offset, tvb_current_offset - tvb_previous_offset,
727                     tvb_get_string_enc(wmem_packet_scope(), tvb, tvb_previous_offset, tvb_current_offset - tvb_previous_offset, ENC_UTF_8|ENC_NA));
728
729     tvb_previous_offset = tvb_current_offset;
730     tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_previous_offset);
731
732     if (tvb_previous_offset == tvb_current_offset) {
733         expert_add_info_format(pinfo, ti, &ei_megaco_parse_error,
734             "[ Parse error: missing SEP in MEGACO header ]");
735         return tvb_current_offset;
736     }
737
738     tvb_previous_offset = tvb_current_offset;
739
740     /* mId should follow here,
741      * mId = (( domainAddress / domainName ) [":" portNumber]) / mtpAddress / deviceName
742      * domainAddress = "[" (IPv4address / IPv6address) "]"
743      * domainName = "<" (ALPHA / DIGIT) *63(ALPHA / DIGIT / "-" /".") ">"
744      * mtpAddress = MTPToken LBRKT 4*8 (HEXDIG) RBRKT
745      * MTPToken = ("MTP")
746      * deviceName = pathNAME
747      * pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )["@" pathDomainName ]
748      */
749
750     tvb_current_offset = tvb_ws_mempbrk_pattern_guint8(tvb, tvb_current_offset, -1, &pbrk_whitespace, &needle);
751     if (tvb_current_offset == -1) {
752         expert_add_info_format(pinfo, ti, &ei_megaco_parse_error,
753             "[ Parse error: no body in MEGACO message (missing SEP after mId) ]");
754         return tvb_captured_length(tvb);
755     }
756
757     tvb_next_offset = megaco_tvb_skip_wsp(tvb, tvb_current_offset);
758
759    /* At this point we should point to the "\n" ending the mId element
760     * or to the next character after white space SEP
761     */
762     megaco_tree_add_string(megaco_tree, hf_megaco_mId, tvb, tvb_previous_offset, tvb_current_offset - tvb_previous_offset,
763                     tvb_get_string_enc(wmem_packet_scope(), tvb, tvb_previous_offset, tvb_current_offset - tvb_previous_offset, ENC_UTF_8|ENC_NA));
764
765     col_clear(pinfo->cinfo, COL_INFO);
766     do{
767     tvb_previous_offset = tvb_next_offset;
768
769 /* Next part is
770  *  : messageBody = ( errorDescriptor / transactionList )
771  *      errorDescriptor = ErrorToken EQUAL ErrorCode LBRKT [quotedString] RBRKT
772  *          ErrorToken = ("Error" / "ER")
773  *
774  *      transactionList = 1*( transactionRequest / transactionReply /
775  *                  transactionPending / transactionResponseAck )
776  *
777  *      transactionResponseAck = ResponseAckToken LBRKT
778  *          transactionAck*(COMMA transactionAck) RBRKT
779  *              ResponseAckToken = ("TransactionResponseAck"/ "K")
780  *
781  *      transactionPending = PendingToken EQUAL TransactionID LBRKT RBRKT
782  *          PendingToken = ("Pending" / "PN")
783  *
784  *      transactionReply = ReplyToken EQUAL TransactionID LBRKT
785  *          [ ImmAckRequiredToken COMMA]( errorDescriptor / actionReplyList ) RBRKT
786  *          ReplyToken = ("Reply" / "P")
787  *
788  *      transactionRequest = TransToken EQUAL TransactionID LBRKT
789  *          actionRequest *(COMMA actionRequest) RBRKT
790  *          TransToken = ("Transaction" / "T")
791  */
792
793     /* Find token length */
794     for (tvb_offset=tvb_previous_offset; tvb_offset < tvb_len-1; tvb_offset++){
795         if (!g_ascii_isalpha(tvb_get_guint8(tvb, tvb_offset ))){
796             break;
797         }
798     }
799     tokenlen = tvb_offset - tvb_previous_offset;
800     token_index = find_megaco_messageBody_names(tvb, tvb_previous_offset, tokenlen);
801     /* Debug code
802         g_warning("token_index %u",token_index);
803     */
804
805     tvb_LBRKT  = tvb_find_guint8(tvb, tvb_offset, tvb_len, '{');
806     tvb_current_offset = tvb_LBRKT;
807     tvb_transaction_end_offset = megaco_tvb_find_token(tvb, tvb_LBRKT - 1, tvb_len);
808
809     switch ( token_index ){
810         /* errorDescriptor */
811         case ERRORTOKEN:
812             col_set_str(pinfo->cinfo, COL_INFO, "Error  ");
813
814             tvb_current_offset = megaco_tvb_find_token(tvb, tvb_offset, tvb_len); /*tvb_find_guint8(tvb, tvb_offset+1, tvb_len, '}');*/
815
816             ti = proto_tree_add_format_text(megaco_tree, tvb, tvb_previous_offset, tvb_current_offset-tvb_previous_offset);
817             message_body_tree = proto_item_add_subtree(ti, ett_megaco_message_body);
818
819             if (tree) {
820                 megaco_tree_add_string(message_body_tree, hf_megaco_transaction, tvb,
821                 tvb_previous_offset, tokenlen,
822                 "Error" );
823
824                 tvb_command_start_offset = tvb_previous_offset;
825                 dissect_megaco_errordescriptor(tvb, pinfo, megaco_tree, tvb_len-1, tvb_command_start_offset);
826             }
827             return tvb_captured_length(tvb);
828             /* transactionResponseAck
829              * transactionResponseAck = ResponseAckToken LBRKT transactionAck
830              *                           *(COMMA transactionAck) RBRKT
831              * transactionAck = transactionID / (transactionID "-" transactionID)
832              */
833         case RESPONSEACKTOKEN:
834             tvb_LBRKT  = tvb_find_guint8(tvb, tvb_offset, tvb_transaction_end_offset, '{');
835             tvb_offset = tvb_LBRKT;
836             save_offset = tvb_previous_offset;
837             save_length = tvb_current_offset-tvb_previous_offset;
838
839             megaco_tree_add_string(megaco_tree, hf_megaco_transaction, tvb,
840                     save_offset, save_length, "TransactionResponseAck" );
841
842             tvb_previous_offset = megaco_tvb_skip_wsp(tvb, tvb_offset+1);
843             tvb_current_offset = tvb_find_guint8(tvb, tvb_offset+1, tvb_len, '}');
844             /*tvb_current_offset = megaco_tvb_find_token(tvb, tvb_offset, tvb_transaction_end_offset);*/
845             tvb_current_offset = megaco_tvb_skip_wsp_return(tvb, tvb_current_offset)-1; /* cut last RBRKT */
846             len = tvb_current_offset - tvb_previous_offset;
847
848             pending_id = (guint)strtoul(tvb_format_text(tvb,tvb_previous_offset,len),NULL,10);
849             col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "%d TransactionResponseAck", pending_id);
850
851             my_proto_tree_add_uint(megaco_tree, hf_megaco_transid, tvb, save_offset, save_length, pending_id);
852
853             if(global_megaco_raw_text){
854                 tvb_raw_text_add(tvb, megaco_tree);
855             }
856             return tvb_captured_length(tvb);
857         /* Pe and PN is transactionPending, P+"any char" is transactionReply */
858         case PENDINGTOKEN:
859
860             tvb_offset  = tvb_find_guint8(tvb, tvb_previous_offset, tvb_transaction_end_offset, '=')+1;
861             tvb_offset = megaco_tvb_skip_wsp(tvb, tvb_offset);
862             tvb_LBRKT  = tvb_find_guint8(tvb, tvb_offset, tvb_transaction_end_offset, '{');
863             tvb_current_offset = tvb_LBRKT;
864             save_offset = tvb_previous_offset;
865             save_length = tvb_current_offset-tvb_previous_offset;
866
867             megaco_tree_add_string(megaco_tree, hf_megaco_transaction, tvb,
868                     save_offset, save_length, "Reply" );
869
870             tvb_current_offset  = megaco_tvb_skip_wsp_return(tvb, tvb_current_offset-1);
871             len = tvb_current_offset - tvb_offset;
872
873             pending_id = (guint)strtoul(tvb_format_text(tvb,tvb_offset,len),NULL,10);
874             col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "%d Pending", pending_id);
875
876             my_proto_tree_add_uint(megaco_tree, hf_megaco_transid, tvb, save_offset, save_length, pending_id);
877             return tvb_captured_length(tvb);
878
879         /* transactionReply */
880         case REPLYTOKEN:
881             trx_type = GCP_TRX_REPLY;
882             tvb_LBRKT  = tvb_find_guint8(tvb, tvb_offset, tvb_transaction_end_offset, '{');
883             save_offset = tvb_previous_offset;
884             save_length = tvb_LBRKT-tvb_previous_offset;
885
886             megaco_tree_add_string(megaco_tree, hf_megaco_transaction, tvb,
887                     save_offset, save_length, "Reply" );
888
889             tvb_offset  = tvb_find_guint8(tvb, tvb_previous_offset, tvb_transaction_end_offset, '=')+1;
890             tvb_offset = megaco_tvb_skip_wsp(tvb, tvb_offset);
891             tvb_current_offset  = megaco_tvb_skip_wsp_return(tvb, tvb_LBRKT-1);
892             len = tvb_current_offset - tvb_offset;
893
894             trx_id = (guint)strtoul(tvb_format_text(tvb,tvb_offset,len),NULL,10);
895             col_add_fstr(pinfo->cinfo, COL_INFO, "%d Reply  ", trx_id);
896
897             my_proto_tree_add_uint(megaco_tree, hf_megaco_transid, tvb, save_offset, save_length, trx_id);
898
899             /* Find if we have a errorDescriptor or actionReplyList */
900             tvb_offset = megaco_tvb_skip_wsp(tvb, tvb_LBRKT+1);
901             tempchar = tvb_get_guint8(tvb,tvb_offset);
902             if ((tempchar == 'E')||(tempchar == 'e')){
903                 dissect_megaco_errordescriptor(tvb, pinfo, megaco_tree, tvb_transaction_end_offset-1, tvb_offset);
904                 return tvb_captured_length(tvb);
905             }
906             /* Offset should be at first printable char after { */
907             tvb_previous_offset = tvb_offset;
908             break;
909         case TRANSTOKEN:
910             /* TransactionRequest   */
911             trx_type = GCP_TRX_REQUEST;
912             save_offset = tvb_previous_offset;
913             save_length = tvb_current_offset-tvb_previous_offset;
914             megaco_tree_add_string(megaco_tree, hf_megaco_transaction, tvb,
915                     save_offset, save_length, "Request" );
916
917             tvb_offset  = tvb_find_guint8(tvb, tvb_offset, tvb_transaction_end_offset, '=')+1;
918             tvb_offset = megaco_tvb_skip_wsp(tvb, tvb_offset);
919             tvb_current_offset  = megaco_tvb_skip_wsp_return(tvb, tvb_current_offset-1);
920             len = tvb_current_offset - tvb_offset;
921
922             trx_id = (guint)strtoul(tvb_format_text(tvb,tvb_offset,len),NULL,10);
923             col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "%d Request", trx_id);
924
925             my_proto_tree_add_uint(megaco_tree, hf_megaco_transid, tvb, save_offset, save_length, trx_id);
926             /* Offset should be at first printable char after { */
927             tvb_previous_offset = megaco_tvb_skip_wsp(tvb, tvb_LBRKT+1);
928
929             break;
930         default :
931             proto_tree_add_expert_format(tree, pinfo, &ei_megaco_error_descriptor_transaction_list, tvb, 0, -1,
932                     "Sorry, can't understand errorDescriptor / transactionList = %s, can't parse it pos %u",
933                         tvb_format_text(tvb,tvb_previous_offset,2),tvb_previous_offset);
934             return tvb_captured_length(tvb);
935         } /* end switch */
936 /*      Only these remains now
937  *      transactionReply = ReplyToken EQUAL TransactionID LBRKT
938  *          [ ImmAckRequiredToken COMMA]( errorDescriptor / actionReplyList ) RBRKT
939  *          ReplyToken = ("Reply" / "P")
940  *
941  *      errorDescriptor   = ErrorToken EQUAL ErrorCode
942  *                     LBRKT [quotedString] RBRKT
943  *
944  *      transactionRequest = TransToken EQUAL TransactionID LBRKT
945  *          actionRequest *(COMMA actionRequest) RBRKT
946  *          TransToken = ("Transaction" / "T")
947  */
948
949         trx = gcp_trx(msg , trx_id , trx_type, keep_persistent_data);
950
951         /* Find Context */
952 nextcontext:
953
954
955
956
957         tvb_next_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_transaction_end_offset, '{');
958         context_offset = tvb_previous_offset;
959         context_length = tvb_next_offset-tvb_previous_offset+1;
960
961         tvb_previous_offset = tvb_find_guint8(tvb, tvb_current_offset, tvb_transaction_end_offset, '=')+1;
962         tvb_previous_offset = megaco_tvb_skip_wsp(tvb, tvb_previous_offset);
963
964         if (tvb_current_offset >= tvb_next_offset) {
965             proto_tree_add_expert_format(megaco_tree, pinfo, &ei_megaco_parse_error,
966                                     tvb, context_offset, context_length, "Parse error: Invalid offset");
967             return tvb_captured_length(tvb);
968         }
969         tvb_current_offset = tvb_next_offset;
970
971
972         tokenlen = tvb_current_offset - tvb_previous_offset;
973         tempchar = tvb_get_guint8(tvb, tvb_previous_offset );
974
975         if (tvb_get_guint8(tvb, tvb_current_offset-1 ) == ' '){
976             tokenlen--;
977         }
978
979         switch ( tempchar ){
980         case '$':
981             ctx_id = CHOOSE_CONTEXT;
982             break;
983         case '*':
984             ctx_id = ALL_CONTEXTS;
985             break;
986         case '-':
987             ctx_id = NULL_CONTEXT;
988             break;
989         default:
990             ctx_id = (guint)strtoul(tvb_format_text(tvb, tvb_previous_offset, tokenlen),NULL,10);
991         }
992
993         my_proto_tree_add_uint(megaco_tree, hf_megaco_Context, tvb, context_offset, context_length, ctx_id);
994         col_append_fstr(pinfo->cinfo, COL_INFO, " |=%s", val_to_str(ctx_id, megaco_context_vals, "%d"));
995
996         ctx = gcp_ctx(msg,trx,ctx_id,keep_persistent_data);
997
998         /* Find Commands */
999
1000         /* If Transaction is is Request, Reply or Pending */
1001         tvb_command_start_offset = megaco_tvb_skip_wsp(tvb, tvb_current_offset +1);
1002         tvb_command_end_offset = tvb_command_start_offset;
1003
1004         tvb_LBRKT = tvb_command_start_offset;
1005         tvb_RBRKT = tvb_command_start_offset;
1006
1007         /* The following loop find the individual contexts, commands and call the for every Descriptor a subroutine */
1008
1009         do {
1010             tvb_command_end_offset = tvb_find_guint8(tvb, tvb_command_end_offset +1,
1011                 tvb_transaction_end_offset, ',');
1012
1013             if ( tvb_command_end_offset == -1 || tvb_command_end_offset > tvb_transaction_end_offset){
1014                 tvb_command_end_offset = tvb_transaction_end_offset ;
1015
1016             }
1017
1018             /* checking how many left brackets are before the next comma */
1019
1020             while ( tvb_find_guint8(tvb, tvb_LBRKT+1,tvb_transaction_end_offset, '{') != -1
1021                 && (tvb_find_guint8(tvb, tvb_LBRKT+1,tvb_transaction_end_offset, '{') < tvb_command_end_offset)){
1022
1023                 tvb_LBRKT = tvb_find_guint8(tvb, tvb_LBRKT+1,
1024                     tvb_transaction_end_offset, '{');
1025
1026                 LBRKT_counter++;
1027             }
1028
1029             /* checking how many right brackets are before the next comma */
1030
1031             while ( (tvb_find_guint8(tvb, tvb_RBRKT+1,tvb_transaction_end_offset, '}') != -1 )
1032                     && (tvb_find_guint8(tvb, tvb_RBRKT+1,tvb_transaction_end_offset, '}') <= tvb_command_end_offset)
1033                 && LBRKT_counter != 0){
1034
1035                 tvb_RBRKT = tvb_find_guint8(tvb, tvb_RBRKT+1,
1036                     tvb_transaction_end_offset, '}');
1037                 RBRKT_counter++;
1038
1039
1040             }
1041
1042             /* If equal or more right brackets before the comma, one command is complete */
1043
1044             if ( LBRKT_counter <= RBRKT_counter ){
1045
1046                 tvb_current_offset  = tvb_find_guint8(tvb, tvb_command_start_offset,
1047                     tvb_transaction_end_offset, '{');
1048
1049
1050                 /* includes no descriptors */
1051
1052                 if ( LBRKT_counter == 0 ){
1053
1054                     tvb_current_offset = tvb_command_end_offset;
1055
1056                     /* the last command in a context */
1057
1058                     if ( tvb_find_guint8(tvb, tvb_command_start_offset, tvb_transaction_end_offset, '}') < tvb_current_offset
1059                         && tvb_find_guint8(tvb, tvb_command_start_offset, tvb_transaction_end_offset, '}') != -1){
1060
1061                         tvb_previous_offset  = tvb_find_guint8(tvb, tvb_command_start_offset,
1062                             tvb_transaction_end_offset, '}');
1063
1064                         len = tvb_previous_offset - tvb_command_start_offset;
1065
1066                         tvb_previous_offset = megaco_tvb_skip_wsp_return(tvb, tvb_previous_offset -1);
1067
1068                         tokenlen =  tvb_previous_offset - tvb_command_start_offset;
1069
1070                     }
1071
1072                     /* not the last command in a context*/
1073
1074                     else{
1075                         len =  tvb_current_offset - tvb_command_start_offset;
1076                         tvb_current_offset = megaco_tvb_skip_wsp_return(tvb, tvb_current_offset -1);
1077
1078                         tokenlen =  tvb_current_offset - tvb_command_start_offset;
1079                     }
1080                 }
1081
1082                 /* command includes descriptors */
1083
1084                 else{
1085                     len =  tvb_current_offset - tvb_command_start_offset;
1086                     tvb_current_offset = megaco_tvb_skip_wsp_return(tvb, tvb_current_offset -1);
1087
1088                     tokenlen =  tvb_current_offset - tvb_command_start_offset;
1089                 }
1090
1091                 /* if a next context is specified */
1092
1093                 if ( tvb_get_guint8(tvb, tvb_command_start_offset ) == 'C'){
1094                     tvb_current_offset = tvb_command_start_offset;
1095                     tvb_previous_offset = tvb_command_start_offset;
1096                     LBRKT_counter = 0;
1097                     RBRKT_counter = 0;
1098                     goto nextcontext;
1099                 }
1100
1101                 megaco_tree_command_line = proto_tree_add_subtree(megaco_tree, tvb, tvb_command_start_offset, len+1, ett_megaco_command_line, &sub_ti, "Command: ");
1102                 /* creation of the megaco_tree_command_line additionally Command and Transaction ID will be printed in this line */
1103                 /* Changed to use the lines above. this code is saved if there is complaints
1104                 sub_ti = proto_tree_add_item(megaco_tree,hf_megaco_command_line,tvb,tvb_command_start_offset,tokenlen, ENC_UTF_8|ENC_NA);
1105                 megaco_tree_command_line = proto_item_add_subtree(sub_ti, ett_megaco_command_line);
1106                 */
1107                 if (!global_megaco_dissect_tree) {
1108                     PROTO_ITEM_SET_HIDDEN(sub_ti);
1109                 }
1110
1111                 tvb_next_offset = tvb_command_start_offset + tokenlen;
1112
1113                 /* Try to dissect Topology Descriptor before the command */
1114                 tempchar = tvb_get_guint8(tvb, tvb_command_start_offset);
1115                 if ( (tempchar >= 'a')&& (tempchar <= 'z')){
1116                     tempchar = tempchar - 0x20;
1117                 }
1118                 if ( tempchar == 'T') {
1119                     tempchar = tvb_get_guint8(tvb, tvb_command_start_offset+1);
1120
1121                     if ( (tempchar >= 'a')&& (tempchar <= 'z'))
1122                         tempchar = tempchar - 0x20;
1123
1124                     if ( tempchar == 'P' || tempchar == 'O'){
1125                         gint tvb_topology_end_offset = tvb_find_guint8(tvb, tvb_command_start_offset, tvb_transaction_end_offset, '}');
1126                         if ( tvb_topology_end_offset == -1 ){
1127                             expert_add_info_format(pinfo, sub_ti, &ei_megaco_parse_error, "Parse error: Missing \"}\"");
1128                             return tvb_captured_length(tvb);
1129                         }
1130
1131                         tvb_command_start_offset = tvb_find_guint8(tvb, tvb_command_start_offset, tvb_transaction_end_offset, '{');
1132                         if ( tvb_command_start_offset == -1 ){
1133                             expert_add_info_format(pinfo, sub_ti, &ei_megaco_parse_error, "Parse error: Missing \"{\"");
1134                             return tvb_captured_length(tvb);
1135                         }
1136                         dissect_megaco_topologydescriptor(tvb, megaco_tree_command_line, tvb_topology_end_offset-1, tvb_command_start_offset+1);
1137
1138                         /* Command after Topology Descriptor */
1139                         tvb_command_start_offset = tvb_find_guint8(tvb, tvb_topology_end_offset + 1,
1140                             tvb_transaction_end_offset, ',');
1141
1142                         if ( tvb_command_start_offset == -1 ){
1143                             /* No Command present after Topology Descriptor */
1144                             break;
1145
1146                         } else {
1147                             /* Try to find the first char of the command */
1148                             tvb_command_start_offset =  megaco_tvb_skip_wsp(tvb, tvb_command_start_offset + 1);
1149                             /*tvb_next_offset = tvb_find_guint8(tvb, tvb_command_start_offset, tvb_transaction_end_offset, '{');*/
1150                             continue;
1151                         }
1152
1153                     }
1154                 }
1155
1156                 /* Additional value */
1157                 if ( tvb_get_guint8(tvb, tvb_command_start_offset ) == 'O'){
1158
1159                     proto_tree_add_item(megaco_tree_command_line, hf_megaco_command_optional, tvb, tvb_command_start_offset, 2, ENC_NA);
1160                     tvb_command_start_offset = tvb_command_start_offset+2;
1161
1162                 }
1163
1164                 /* Additional value */
1165                 if ( tvb_get_guint8(tvb, tvb_command_start_offset ) == 'W'){
1166
1167                     proto_tree_add_item(megaco_tree_command_line, hf_megaco_wildcard_response, tvb, tvb_command_start_offset, 2, ENC_NA );
1168                     tvb_command_start_offset = tvb_command_start_offset+2;
1169                 }
1170
1171                 tvb_offset  = tvb_find_guint8(tvb, tvb_command_start_offset,
1172                     tvb_transaction_end_offset, '=');
1173                 if (tvb_offset == -1 ) {
1174                     proto_tree_add_expert_format(megaco_tree, pinfo, &ei_megaco_parse_error, tvb, tvb_command_start_offset, len+1, "Parse error: Missing \"=\"");
1175                     return tvb_captured_length(tvb);
1176                 }
1177                 tvb_offset = megaco_tvb_skip_wsp_return(tvb, tvb_offset -1);
1178                 tokenlen = tvb_offset - tvb_command_start_offset;
1179
1180                 tempchar = tvb_get_guint8(tvb, tvb_command_start_offset);
1181                 if ( (tempchar >= 'a')&& (tempchar <= 'z'))
1182                     tempchar = tempchar - 0x20;
1183
1184                 if ( tempchar != 'E' ){
1185                     /* Short form used */
1186                     if (short_form){
1187
1188                         switch ( tempchar ){
1189
1190                         case 'A':
1191
1192                             tempchar = tvb_get_guint8(tvb, tvb_command_start_offset+1);
1193                             if ( (tempchar >= 'a')&& (tempchar <= 'z'))
1194                                 tempchar = tempchar - 0x20;
1195
1196                             switch ( tempchar ){
1197
1198                             case 'V':
1199                                 switch(trx_type) {
1200                                     case GCP_TRX_REQUEST: cmd_type = GCP_CMD_AUDITVAL_REPLY; break;
1201                                     case GCP_TRX_REPLY: cmd_type = GCP_CMD_AUDITVAL_REQ; break;
1202                                     default: cmd_type = GCP_CMD_NONE; break;
1203                                 }
1204
1205                                 proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
1206                                     tvb_command_start_offset, tokenlen, "AuditValue");
1207                                 col_append_str(pinfo->cinfo, COL_INFO, " AuditValue");
1208                                 proto_item_append_text(sub_ti, "AuditValue");
1209                                 break;
1210
1211                             case 'C':
1212                                 switch(trx_type) {
1213                                     case GCP_TRX_REQUEST: cmd_type = GCP_CMD_AUDITCAP_REQ; break;
1214                                     case GCP_TRX_REPLY: cmd_type = GCP_CMD_AUDITCAP_REPLY; break;
1215                                     default: cmd_type = GCP_CMD_NONE; break;
1216                                 }
1217                                 proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
1218                                     tvb_command_start_offset, tokenlen, "AuditCapability");
1219                                 col_append_str(pinfo->cinfo, COL_INFO, " AuditCapability");
1220                                 proto_item_append_text(sub_ti, "AuditCapability");
1221                                 break;
1222
1223                             default:
1224                                 switch(trx_type) {
1225                                     case GCP_TRX_REQUEST: cmd_type = GCP_CMD_ADD_REQ; break;
1226                                     case GCP_TRX_REPLY: cmd_type = GCP_CMD_ADD_REPLY; break;
1227                                     default: cmd_type = GCP_CMD_NONE; break;
1228                                 }
1229
1230                                 proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
1231                                     tvb_command_start_offset, tokenlen, "Add");
1232                                 col_append_str(pinfo->cinfo, COL_INFO, " Add");
1233                                 proto_item_append_text(sub_ti, "Add");
1234                                 break;
1235                             }
1236                             break;
1237
1238                         case 'I':
1239                             /* "IEPS" */
1240                             tempchar = tvb_get_guint8(tvb, tvb_command_start_offset+1);
1241                             if(tempchar == 'E'){
1242                                 proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
1243                                     tvb_command_start_offset, tokenlen, "IEPSCall");
1244                                 col_append_str(pinfo->cinfo, COL_INFO, " IEPSCall");
1245                                 proto_item_append_text(sub_ti, "IEPSCall");
1246                             }
1247                             cmd_type = GCP_CMD_NONE;
1248                             break;
1249                         case 'N':
1250                             switch(trx_type) {
1251                                 case GCP_TRX_REQUEST: cmd_type = GCP_CMD_NOTIFY_REQ; break;
1252                                 case GCP_TRX_REPLY: cmd_type = GCP_CMD_NOTIFY_REPLY; break;
1253                                 default: cmd_type = GCP_CMD_NONE; break;
1254                             }
1255
1256                             proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
1257                                 tvb_command_start_offset, tokenlen, "Notify");
1258                             col_append_str(pinfo->cinfo, COL_INFO, " Notify");
1259                             proto_item_append_text(sub_ti, "Notify");
1260                             break;
1261
1262                         case 'M':
1263
1264                             tempchar = tvb_get_guint8(tvb, tvb_command_start_offset+1);
1265                             if ( (tempchar >= 'a')&& (tempchar <= 'z'))
1266                                 tempchar = tempchar - 0x20;
1267
1268                             switch ( tempchar ){
1269                             case 'F':
1270                                 switch(trx_type) {
1271                                     case GCP_TRX_REQUEST: cmd_type = GCP_CMD_MOD_REQ; break;
1272                                     case GCP_TRX_REPLY: cmd_type = GCP_CMD_MOD_REPLY; break;
1273                                     default: cmd_type = GCP_CMD_NONE; break;
1274                                 }
1275
1276                                 proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
1277                                     tvb_command_start_offset, tokenlen, "Modify");
1278                                 col_append_str(pinfo->cinfo, COL_INFO, " Modify");
1279                                 proto_item_append_text(sub_ti, "Modify");
1280                                 break;
1281
1282                             case 'V':
1283                                 switch(trx_type) {
1284                                     case GCP_TRX_REQUEST: cmd_type = GCP_CMD_MOVE_REQ; break;
1285                                     case GCP_TRX_REPLY: cmd_type = GCP_CMD_MOVE_REPLY; break;
1286                                     default: cmd_type = GCP_CMD_NONE; break;
1287                                 }
1288                                 proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
1289                                     tvb_command_start_offset, tokenlen, "Move");
1290                                 col_append_str(pinfo->cinfo, COL_INFO, " Move");
1291                                 proto_item_append_text(sub_ti, "Move");
1292                                 break;
1293                             }
1294                             break;
1295
1296                         case 'P':
1297                             cmd_type = GCP_CMD_NONE;
1298                             /*
1299                             PackagesToken   = ("Packages"   / "PG")
1300                             PendingToken    = ("Pending"    / "PN")
1301                             PriorityToken   = ("Priority"   / "PR")
1302                             ProfileToken    = ("Profile"    / "PF")
1303                             */
1304                             tempchar = tvb_get_guint8(tvb, tvb_command_start_offset+1);
1305                             if ( (tempchar >= 'a')&& (tempchar <= 'z'))
1306                                 tempchar = tempchar - 0x20;
1307
1308                             switch ( tempchar ){
1309                             case 'G':
1310                                 proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
1311                                     tvb_command_start_offset, tokenlen, "Packages");
1312                                 col_append_str(pinfo->cinfo, COL_INFO, " Packages");
1313                                 proto_item_append_text(sub_ti, "Packages");
1314                                 break;
1315                             case 'N':
1316                                 proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
1317                                     tvb_command_start_offset, tokenlen, "Pending");
1318                                 col_append_str(pinfo->cinfo, COL_INFO, " Pending");
1319                                 proto_item_append_text(sub_ti, "Pending");
1320                                 break;
1321                             case 'R':
1322                                 proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
1323                                     tvb_command_start_offset, tokenlen, "Priority");
1324                                 col_append_str(pinfo->cinfo, COL_INFO, " Priority");
1325                                 proto_item_append_text(sub_ti, "Priority");
1326                                 break;
1327                             case 'F':
1328                                 proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
1329                                     tvb_command_start_offset, tokenlen, "Profile");
1330                                 col_append_str(pinfo->cinfo, COL_INFO, " Profile");
1331                                 proto_item_append_text(sub_ti, "Profile");
1332                                 break;
1333                             }
1334                             break;
1335
1336                         case 'S':
1337                             tempchar = tvb_get_guint8(tvb, tvb_command_start_offset+1);
1338                             if ( (tempchar >= 'a')&& (tempchar <= 'z'))
1339                                 tempchar = tempchar - 0x20;
1340
1341                             switch ( tempchar ){
1342
1343                             case 'C':
1344                                 switch(trx_type) {
1345                                     case GCP_TRX_REQUEST: cmd_type = GCP_CMD_SVCCHG_REQ; break;
1346                                     case GCP_TRX_REPLY: cmd_type = GCP_CMD_SVCCHG_REPLY; break;
1347                                     default: cmd_type = GCP_CMD_NONE; break;
1348                                 }
1349                                 proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
1350                                     tvb_command_start_offset, tokenlen, "ServiceChange");
1351                                 col_append_str(pinfo->cinfo, COL_INFO, " ServiceChange");
1352                                 proto_item_append_text(sub_ti, "ServiceChange");
1353                                 break;
1354
1355                             default:
1356                                 switch(trx_type) {
1357                                     case GCP_TRX_REQUEST: cmd_type = GCP_CMD_SUB_REQ; break;
1358                                     case GCP_TRX_REPLY: cmd_type = GCP_CMD_SUB_REPLY; break;
1359                                     default: cmd_type = GCP_CMD_NONE; break;
1360                                 }
1361                                 proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
1362                                     tvb_command_start_offset, tokenlen, "Subtract");
1363                                 col_append_str(pinfo->cinfo, COL_INFO, " Subtract");
1364                                 proto_item_append_text(sub_ti, "Subtract");
1365                                 break;
1366                             }
1367                             break;
1368
1369                         default:
1370                             proto_item_append_text(sub_ti, "<None> 0x%02x", tempchar);
1371                             expert_add_info(pinfo, sub_ti, &ei_megaco_no_command);
1372                             return tvb_captured_length(tvb);
1373                         }
1374                     }
1375                     else{
1376                         gchar* command = tvb_format_text(tvb, tvb_command_start_offset, tokenlen);
1377
1378                         if ( g_str_equal(command,"Subtract") ) {
1379                             switch(trx_type) {
1380                                 case GCP_TRX_REQUEST: cmd_type = GCP_CMD_SUB_REQ; break;
1381                                 case GCP_TRX_REPLY: cmd_type = GCP_CMD_SUB_REPLY; break;
1382                                 default: cmd_type = GCP_CMD_NONE; break;
1383                             }
1384                         } else if ( g_str_equal(command,"AuditValue") ) {
1385                             switch(trx_type) {
1386                                 case GCP_TRX_REQUEST: cmd_type = GCP_CMD_AUDITVAL_REPLY; break;
1387                                 case GCP_TRX_REPLY: cmd_type = GCP_CMD_AUDITVAL_REQ; break;
1388                                 default: cmd_type = GCP_CMD_NONE; break;
1389                             }
1390                         } else if ( g_str_equal(command,"AuditCapability") ) {
1391                             switch(trx_type) {
1392                                 case GCP_TRX_REQUEST: cmd_type = GCP_CMD_AUDITCAP_REQ; break;
1393                                 case GCP_TRX_REPLY: cmd_type = GCP_CMD_AUDITCAP_REPLY; break;
1394                                 default: cmd_type = GCP_CMD_NONE; break;
1395                             }
1396                         } else if ( g_str_equal(command,"Add") ) {
1397                             switch(trx_type) {
1398                                 case GCP_TRX_REQUEST: cmd_type = GCP_CMD_ADD_REQ; break;
1399                                 case GCP_TRX_REPLY: cmd_type = GCP_CMD_ADD_REPLY; break;
1400                                 default: cmd_type = GCP_CMD_NONE; break;
1401                             }
1402                         } else if ( g_str_equal(command,"Notify") ) {
1403                             switch(trx_type) {
1404                                 case GCP_TRX_REQUEST: cmd_type = GCP_CMD_NOTIFY_REQ; break;
1405                                 case GCP_TRX_REPLY: cmd_type = GCP_CMD_NOTIFY_REPLY; break;
1406                                 default: cmd_type = GCP_CMD_NONE; break;
1407                             }
1408                         } else if ( g_str_equal(command,"Modify") ) {
1409                             switch(trx_type) {
1410                                 case GCP_TRX_REQUEST: cmd_type = GCP_CMD_MOD_REQ; break;
1411                                 case GCP_TRX_REPLY: cmd_type = GCP_CMD_MOD_REPLY; break;
1412                                 default: cmd_type = GCP_CMD_NONE; break;
1413                             }
1414                         } else if ( g_str_equal(command,"Move") ) {
1415                             switch(trx_type) {
1416                                 case GCP_TRX_REQUEST: cmd_type = GCP_CMD_MOVE_REQ; break;
1417                                 case GCP_TRX_REPLY: cmd_type = GCP_CMD_MOVE_REPLY; break;
1418                                 default: cmd_type = GCP_CMD_NONE; break;
1419                             }
1420                         } else if ( g_str_equal(command,"ServiceChange") ) {
1421                             switch(trx_type) {
1422                                 case GCP_TRX_REQUEST: cmd_type = GCP_CMD_SVCCHG_REQ; break;
1423                                 case GCP_TRX_REPLY: cmd_type = GCP_CMD_SVCCHG_REPLY; break;
1424                                 default: cmd_type = GCP_CMD_NONE; break;
1425                             }
1426                         } else if ( g_str_equal(command,"Subtract") ) {
1427                             switch(trx_type) {
1428                                 case GCP_TRX_REQUEST: cmd_type = GCP_CMD_SUB_REQ; break;
1429                                 case GCP_TRX_REPLY: cmd_type = GCP_CMD_SUB_REPLY; break;
1430                                 default: cmd_type = GCP_CMD_NONE; break;
1431                             }
1432                         } else {
1433                             switch(trx_type) {
1434                                 case GCP_TRX_REQUEST: cmd_type = GCP_CMD_OTHER_REQ; break;
1435                                 case GCP_TRX_REPLY: cmd_type = GCP_CMD_REPLY; break;
1436                                 default: cmd_type = GCP_CMD_NONE; break;
1437                             }
1438                         }
1439
1440
1441                         proto_tree_add_string(megaco_tree_command_line, hf_megaco_command, tvb,
1442                             tvb_command_start_offset, tokenlen, command);
1443                         col_append_fstr(pinfo->cinfo, COL_INFO, " %s", command);
1444                         proto_item_append_text(sub_ti, " %s", command);
1445                     }
1446
1447                     if (cmd_type == GCP_CMD_NONE && trx_type == GCP_TRX_REPLY) {
1448                         cmd_type = GCP_CMD_REPLY;
1449                     }
1450
1451                     if (cmd_type != GCP_CMD_NONE) {
1452                         cmd = gcp_cmd(msg, trx, ctx, cmd_type, tvb_command_start_offset, keep_persistent_data);
1453                         tap_queue_packet(megaco_tap, pinfo, cmd);
1454                     }
1455
1456                     tvb_offset  = tvb_find_guint8(tvb, tvb_command_start_offset,
1457                         tvb_transaction_end_offset, '=');
1458                     if (tvb_offset == -1 ) {
1459                         expert_add_info_format(pinfo, sub_ti, &ei_megaco_parse_error, "Parse error: Missing \"=\"");
1460                         return tvb_captured_length(tvb);
1461                     }
1462                     tvb_offset = megaco_tvb_skip_wsp(tvb, tvb_offset+1);
1463                     tokenlen = tvb_next_offset - tvb_offset;
1464                     if (tokenlen+1 <= 0) {
1465                         expert_add_info_format(pinfo, sub_ti, &ei_megaco_parse_error, "Parse error: Invalid token length (%d)", tokenlen+1);
1466                         return tvb_captured_length(tvb);
1467                     }
1468
1469                     tempchar = tvb_get_guint8(tvb, tvb_offset);
1470                     if ( (tempchar >= 'a')&& (tempchar <= 'z'))
1471                         tempchar = tempchar - 0x20;
1472
1473                     term = wmem_new0(wmem_packet_scope(), gcp_term_t);
1474                     wild_term = GCP_WILDCARD_NONE;
1475                     term->type = GCP_TERM_TYPE_UNKNOWN;
1476
1477                     switch ( tempchar ){
1478
1479                     case 'E':
1480                         if ((tokenlen+1 > (int) sizeof(TermID))) {
1481                             expert_add_info_format(pinfo, sub_ti, &ei_megaco_parse_error, "Parse error: Invalid TermID length (%d)", tokenlen+1);
1482                             return tvb_captured_length(tvb);
1483                         }
1484                         tvb_get_nstringz0(tvb,tvb_offset,tokenlen+1,TermID);
1485                         TermID[0] = 'e';
1486
1487                         term->len = tokenlen;
1488                         term->str = (const gchar*)(term->buffer = TermID);
1489
1490                         gcp_cmd_add_term(msg, trx, cmd, term, wild_term, keep_persistent_data);
1491
1492                         /*** TERM ***/
1493                         proto_tree_add_string(megaco_tree_command_line, hf_megaco_termid, tvb,
1494                             tvb_offset, tokenlen, TermID);
1495                         break;
1496
1497                     case '*':
1498                         wild_term = GCP_WILDCARD_ALL;
1499                         term->len = 1;
1500                         term->buffer = (const guint8*)(term->str = "*");
1501
1502                         gcp_cmd_add_term(msg, trx, cmd, term, wild_term, keep_persistent_data);
1503
1504                         proto_tree_add_string(megaco_tree_command_line, hf_megaco_termid, tvb,
1505                             tvb_offset, tokenlen,
1506                             "WildCard all");
1507                             col_append_str(pinfo->cinfo, COL_INFO, "=*");
1508                         break;
1509
1510                     case '$':
1511                         wild_term = GCP_WILDCARD_CHOOSE;
1512
1513                         term->len = 1;
1514                         term->buffer = (term->str = "$");
1515
1516                         gcp_cmd_add_term(msg, trx, cmd, term, wild_term, keep_persistent_data);
1517
1518                         proto_tree_add_string(megaco_tree_command_line, hf_megaco_termid, tvb,
1519                             tvb_offset, tokenlen,
1520                             "WildCard any");
1521                             col_append_str(pinfo->cinfo, COL_INFO, "=$");
1522                         break;
1523                     case 'O':
1524                         break;
1525
1526                     default:
1527                         /*** TERM ***/
1528                         proto_tree_add_string(megaco_tree_command_line, hf_megaco_termid, tvb,
1529                             tvb_offset, tokenlen,
1530                             tvb_format_text(tvb, tvb_offset,
1531                             tokenlen));
1532
1533                         term->len = tokenlen;
1534                         term->buffer = (const guint8*)(term->str = tvb_format_text(tvb, tvb_offset, tokenlen));
1535
1536                         gcp_cmd_add_term(msg, trx, cmd, term, wild_term, keep_persistent_data);
1537
1538                         col_append_fstr(pinfo->cinfo, COL_INFO, "=%s",tvb_format_text(tvb, tvb_offset,tokenlen));
1539                         break;
1540                     }
1541
1542             }
1543             /* Dissect the Descriptors */
1544
1545
1546             if ( LBRKT_counter != 0 && tvb_current_offset != tvb_command_end_offset){
1547
1548                 tvb_descriptors_start_offset  = tvb_find_guint8(tvb, tvb_command_start_offset,
1549                     tvb_transaction_end_offset, '{');
1550
1551                 tvb_descriptors_end_offset = tvb_descriptors_start_offset;
1552                 if ( tvb_descriptors_end_offset > tvb_transaction_end_offset )
1553                     tvb_descriptors_end_offset = tvb_transaction_end_offset;
1554
1555                 while ( LBRKT_counter > 0 ){
1556
1557                     tvb_descriptors_end_offset = tvb_find_guint8(tvb, tvb_descriptors_end_offset+1,
1558                         tvb_transaction_end_offset, '}');
1559
1560                     LBRKT_counter--;
1561
1562                 }
1563
1564                 tempchar = tvb_get_guint8(tvb, tvb_command_start_offset);
1565
1566                 if ( tempchar == 'E'|| tempchar == 'e'){
1567                     dissect_megaco_descriptors(tvb, megaco_tree_command_line, pinfo, tvb_command_start_offset-1,tvb_descriptors_end_offset, tree);
1568                 }
1569                 else {
1570                     dissect_megaco_descriptors(tvb, megaco_tree_command_line, pinfo, tvb_descriptors_start_offset,tvb_descriptors_end_offset, tree);
1571                 }
1572             }
1573             RBRKT_counter = 0;
1574             LBRKT_counter = 0;
1575             tvb_command_start_offset = megaco_tvb_skip_wsp(tvb, tvb_command_end_offset +1);
1576             tvb_LBRKT = tvb_command_start_offset;
1577             tvb_RBRKT = tvb_command_start_offset;
1578
1579             }
1580
1581         } while ( tvb_command_end_offset < tvb_transaction_end_offset );
1582
1583         if (keep_persistent_data) {
1584             gcp_msg_to_str(msg,keep_persistent_data);
1585             gcp_analyze_msg(megaco_tree, pinfo, tvb, msg, &megaco_ctx_ids, &ei_megaco_errored_command);
1586         }
1587
1588         tvb_next_offset = tvb_transaction_end_offset;
1589     }
1590     while( tvb_transaction_end_offset > 0 && tvb_transaction_end_offset < tvb_len - 2);
1591
1592     if(global_megaco_raw_text){
1593         tvb_raw_text_add(tvb, megaco_tree);
1594     }
1595
1596     return tvb_captured_length(tvb);
1597 }
1598
1599 #define MEGACO_MODEM_TOKEN          1
1600 #define MEGACO_MUX_TOKEN            2
1601 #define MEGACO_MEDIA_TOKEN          3
1602 #define MEGACO_SIGNALS_TOKEN        4
1603 #define MEGACO_SERVICES_TOKEN       5
1604 #define MEGACO_STATS_TOKEN          6
1605 #define MEGACO_ERROR_TOKEN          7
1606 #define MEGACO_EVENTS_TOKEN         8
1607 #define MEGACO_AUDIT_TOKEN          9
1608 #define MEGACO_DIGITMAP_TOKEN       10
1609 #define MEGACO_OE_TOKEN             11
1610 #define MEGACO_TOPOLOGY_TOKEN       12
1611 #define MEGACO_PACKAGES_TOKEN       13
1612
1613 static const megaco_tokens_t megaco_descriptors_names[] = {
1614     { "Unknown-token",              NULL }, /* 0 Pad so that the real headers start at index 1 */
1615     { "Modem",                      "MD" }, /* 1 */
1616     { "Mux",                        "MX" }, /* 2 */
1617     { "Media",                      "M" },  /* 3 */
1618     { "Signals",                    "SG" }, /* 4 */
1619     { "Services",                   "SV" }, /* 5 */
1620     { "Statistics",                 "SA" }, /* 6 */
1621     { "Error",                      "ER" }, /* 7 */
1622     { "Events",                     "E" },  /* 8 */
1623     { "Audit",                      "AT" }, /* 9 */
1624     { "DigitMap",                   "DM" }, /* 10 */
1625     { "ObservedEvents",             "OE" }, /* 11 */
1626     { "Topology",                   "TP" }, /* 12 */
1627     { "Packages",                   "PG" }, /* 13 */
1628 };
1629
1630 /* Returns index of megaco_tokens_t */
1631 /* note - also called by dissect_megaco_auditdescriptor */
1632 static gint find_megaco_descriptors_names(tvbuff_t *tvb, int offset, guint header_len)
1633 {
1634     guint i;
1635
1636     for (i = 1; i < array_length(megaco_descriptors_names); i++) {
1637         if (header_len == strlen(megaco_descriptors_names[i].name) &&
1638             tvb_strncaseeql(tvb, offset, megaco_descriptors_names[i].name, header_len) == 0)
1639             return i;
1640         if (megaco_descriptors_names[i].compact_name != NULL &&
1641             header_len == strlen(megaco_descriptors_names[i].compact_name) &&
1642             tvb_strncaseeql(tvb, offset, megaco_descriptors_names[i].compact_name, header_len) == 0)
1643             return i;
1644     }
1645     return -1;
1646 }
1647
1648 static void
1649 dissect_megaco_modemdescriptor(tvbuff_t *tvb, proto_tree *megaco_tree_command_line,  gint tvb_RBRKT, gint tvb_previous_offset)
1650 {
1651
1652     gint    tokenlen;
1653
1654     tokenlen =  (tvb_RBRKT+1) - tvb_previous_offset;
1655     proto_tree_add_string(megaco_tree_command_line, hf_megaco_modem_descriptor, tvb,
1656                             tvb_previous_offset, tokenlen,
1657                             tvb_format_text(tvb, tvb_previous_offset,
1658                             tokenlen));
1659
1660 }
1661 static void
1662 dissect_megaco_multiplexdescriptor(tvbuff_t *tvb, proto_tree *megaco_tree_command_line,  gint tvb_RBRKT, gint tvb_previous_offset)
1663 {
1664
1665     gint    tokenlen;
1666
1667     tokenlen =  (tvb_RBRKT+1) - tvb_previous_offset;
1668     proto_tree_add_string(megaco_tree_command_line, hf_megaco_multiplex_descriptor, tvb,
1669                             tvb_previous_offset, tokenlen,
1670                             tvb_format_text(tvb, tvb_previous_offset,
1671                             tokenlen));
1672
1673 }
1674
1675 /* mediaDescriptor = MediaToken LBRKT mediaParm *(COMMA mediaParm) RBRKT
1676  *  MediaToken = ("Media" / "M")
1677  *
1678  *      mediaParm = (streamParm / streamDescriptor /terminationStateDescriptor)
1679  *
1680  *  ; at-most one terminationStateDescriptor
1681  *  ; and either streamParm(s) or streamDescriptor(s) but not both
1682  *          streamParm = ( localDescriptor / remoteDescriptor /localControlDescriptor )
1683  *              localDescriptor = LocalToken LBRKT octetString RBRKT
1684  *                          LocalToken = ("Local" / "L")
1685  *                          octetString = *(nonEscapeChar)
1686  *                                  nonEscapeChar = ( "\}" / %x01-7C / %x7E-FF )
1687  *              remoteDescriptor = RemoteToken LBRKT octetString RBRKT
1688  *                          RemoteToken = ("Remote" / "R")
1689  *              localControlDescriptor = LocalControlToken LBRKT localParm*(COMMA localParm) RBRKT
1690  *                          LocalControlToken = ("LocalControl" / "O")
1691  *                          localParm = ( streamMode / propertyParm / reservedValueMode
1692  *          streamDescriptor = StreamToken EQUAL StreamID LBRKT streamParm*(COMMA streamParm) RBRKT
1693  *                          StreamToken = ("Stream" / "ST")
1694  *          terminationStateDescriptor = TerminationStateToken LBRKTterminationStateParm
1695  *                              *( COMMA terminationStateParm ) RBRKT
1696  *                          TerminationStateToken = ("TerminationState" / "TS")
1697  *                          terminationStateParm =(propertyParm / serviceStates / eventBufferControl )
1698  */
1699
1700 #define MEGACO_LOCAL_TOKEN              1
1701 #define MEGACO_REMOTE_TOKEN             2
1702 #define MEGACO_LOCAL_CONTROL_TOKEN      3
1703 #define MEGACO_STREAM_TOKEN             4
1704 #define MEGACO_TERMINATION_STATE_DESC   5
1705
1706 static const megaco_tokens_t megaco_mediaParm_names[] = {
1707     { "Unknown-token",              NULL }, /* 0 Pad so that the real headers start at index 1 */
1708     { "Local",                      "L" },  /* 1 */
1709     { "Remote",                     "R" },  /* 2 */
1710     { "LocalControl",               "O" },  /* 3 */
1711     { "Stream",                     "ST" }, /* 4 */
1712     { "TerminationState",           "TS" }, /* 5 */
1713 };
1714
1715 /* Returns index of megaco_tokens_t */
1716 static gint find_megaco_mediaParm_names(tvbuff_t *tvb, int offset, guint header_len)
1717 {
1718     guint i;
1719
1720     for (i = 1; i < array_length(megaco_mediaParm_names); i++) {
1721         if (header_len == strlen(megaco_mediaParm_names[i].name) &&
1722             tvb_strncaseeql(tvb, offset, megaco_mediaParm_names[i].name, header_len) == 0)
1723             return i;
1724         if (megaco_mediaParm_names[i].compact_name != NULL &&
1725             header_len == strlen(megaco_mediaParm_names[i].compact_name) &&
1726             tvb_strncaseeql(tvb, offset, megaco_mediaParm_names[i].compact_name, header_len) == 0)
1727             return i;
1728     }
1729
1730     return -1;
1731 }
1732
1733 static void
1734 dissect_megaco_mediadescriptor(tvbuff_t *tvb, proto_tree *megaco_tree_command_line,packet_info *pinfo,  gint tvb_last_RBRKT,
1735                                 gint tvb_previous_offset, gint start_offset, proto_tree *top_tree)
1736 {
1737
1738     gint    tokenlen, tvb_LBRKT, tvb_RBRKT;
1739     gint    tvb_next_offset, tvb_current_offset, tvb_offset, equal_offset, save_offset;
1740     gint    mediaParm;
1741     guint   streamId;
1742
1743     proto_tree  *megaco_mediadescriptor_tree;
1744     proto_item  *megaco_mediadescriptor_ti, *ti;
1745
1746     megaco_mediadescriptor_ti = proto_tree_add_item(megaco_tree_command_line, hf_megaco_media_descriptor, tvb, start_offset, 1, ENC_NA);
1747     megaco_mediadescriptor_tree = proto_item_add_subtree(megaco_mediadescriptor_ti, ett_megaco_mediadescriptor);
1748
1749     while ( tvb_previous_offset < tvb_last_RBRKT){
1750         /* Start of token */
1751         tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_previous_offset);
1752
1753         /* Find token length */
1754         for (tvb_next_offset=tvb_current_offset; tvb_next_offset < tvb_last_RBRKT; tvb_next_offset++){
1755                 if (!g_ascii_isalpha(tvb_get_guint8(tvb, tvb_next_offset ))){
1756                 break;
1757             }
1758         }
1759         tokenlen = tvb_next_offset - tvb_current_offset;
1760
1761         mediaParm = find_megaco_mediaParm_names(tvb, tvb_current_offset, tokenlen);
1762
1763         tvb_LBRKT = tvb_find_guint8(tvb, tvb_next_offset , tvb_last_RBRKT, '{');
1764         tvb_next_offset = tvb_find_guint8(tvb, tvb_current_offset+1 , tvb_last_RBRKT, '}');
1765         tvb_RBRKT = tvb_next_offset;
1766
1767         switch ( mediaParm ){
1768         case MEGACO_LOCAL_TOKEN:
1769             tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_LBRKT+1);
1770             dissect_megaco_Localdescriptor(tvb, megaco_mediadescriptor_tree, pinfo,
1771                 tvb_RBRKT, tvb_current_offset);
1772             tvb_current_offset = tvb_RBRKT;
1773             break;
1774         case MEGACO_REMOTE_TOKEN:
1775             tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_LBRKT+1);
1776             dissect_megaco_Localdescriptor(tvb, megaco_mediadescriptor_tree, pinfo,
1777                 tvb_RBRKT, tvb_current_offset);
1778             tvb_current_offset = tvb_RBRKT;
1779             break;
1780         case MEGACO_LOCAL_CONTROL_TOKEN:
1781             tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_LBRKT+1);
1782             dissect_megaco_LocalControldescriptor(tvb, megaco_mediadescriptor_tree, pinfo,
1783                 tvb_RBRKT, tvb_current_offset, top_tree);
1784             tvb_current_offset = tvb_RBRKT;
1785             break;
1786         case MEGACO_STREAM_TOKEN:
1787             save_offset = tvb_current_offset;
1788             equal_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_last_RBRKT, '=');
1789             tvb_current_offset = megaco_tvb_skip_wsp(tvb, equal_offset+1);
1790             tvb_offset = megaco_tvb_skip_wsp_return(tvb, tvb_LBRKT-1);
1791             tokenlen =  tvb_offset - tvb_current_offset;
1792
1793             streamId = (guint)strtoul(tvb_format_text(tvb, tvb_current_offset,tokenlen),NULL,10);
1794             ti = proto_tree_add_uint(megaco_mediadescriptor_tree, hf_megaco_streamid, tvb,
1795                 save_offset, 1, streamId);
1796             proto_item_set_len(ti, tvb_offset-save_offset+tokenlen);
1797             tvb_previous_offset = tvb_LBRKT+1;
1798             continue;
1799         case MEGACO_TERMINATION_STATE_DESC:
1800             tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_LBRKT+1);
1801             dissect_megaco_TerminationStatedescriptor(tvb, megaco_mediadescriptor_tree,
1802                 tvb_RBRKT, tvb_current_offset);
1803             tvb_current_offset = tvb_RBRKT;
1804             break;
1805         default:
1806             break;
1807         };
1808         /* more parameters ? */
1809         tvb_next_offset = tvb_find_guint8(tvb, tvb_current_offset+1 , tvb_last_RBRKT, ',');
1810         if (tvb_next_offset > tvb_last_RBRKT) tvb_next_offset = tvb_last_RBRKT;
1811         if ( tvb_next_offset != -1 ){
1812             /* (raw formatting removed)
1813                tokenlen = tvb_next_offset - tvb_RBRKT+1;
1814                proto_tree_add_format_text(megaco_mediadescriptor_tree, tvb, tvb_RBRKT, tokenlen); */
1815             tvb_previous_offset = tvb_next_offset+1;
1816         } else{
1817             /* Add the trailing '}' (raw formatting removed) */
1818             /* proto_tree_add_format_text(megaco_mediadescriptor_tree, tvb, tvb_RBRKT, 1); */
1819             tvb_previous_offset = tvb_last_RBRKT;
1820         }
1821
1822     } /* End while */
1823
1824     proto_item_set_end(megaco_mediadescriptor_ti, tvb, tvb_previous_offset);
1825 }
1826
1827 static void
1828 dissect_megaco_h245(tvbuff_t *tvb, packet_info *pinfo, proto_tree *megaco_tree, gint offset, gint len, proto_tree *top_tree)
1829 {
1830     /*proto_item *item;*/
1831     /*proto_tree *tree;*/
1832     gchar *msg = tvb_format_text(tvb, offset, len);
1833
1834     /*item= */proto_tree_add_item(megaco_tree, hf_megaco_h245, tvb, offset, len, ENC_NA);
1835     /*tree = proto_item_add_subtree(item, ett_megaco_h245); */
1836
1837     /* arbitrary maximum length */
1838     if(len<20480){
1839         int i;
1840         tvbuff_t *h245_tvb;
1841         guint8 *buf = (guint8 *)wmem_alloc(pinfo->pool, 10240);
1842
1843         /* first, skip to where the encoded pdu starts, this is
1844            the first hex digit after the '=' char.
1845         */
1846         while(1){
1847             if((*msg==0)||(*msg=='\n')){
1848                 return;
1849             }
1850             if(*msg=='='){
1851                 msg++;
1852                 break;
1853             }
1854             msg++;
1855         }
1856         while(1){
1857             if((*msg==0)||(*msg=='\n')){
1858                 return;
1859             }
1860             if( ((*msg>='0')&&(*msg<='9'))
1861             ||  ((*msg>='a')&&(*msg<='f'))
1862             ||  ((*msg>='A')&&(*msg<='F'))){
1863                 break;
1864             }
1865             msg++;
1866         }
1867         i=0;
1868         while( ((*msg>='0')&&(*msg<='9'))
1869              ||((*msg>='a')&&(*msg<='f'))
1870              ||((*msg>='A')&&(*msg<='F'))  ){
1871             int val;
1872             if((*msg>='0')&&(*msg<='9')){
1873                 val=(*msg)-'0';
1874             } else if((*msg>='a')&&(*msg<='f')){
1875                 val=(*msg)-'a'+10;
1876             } else if((*msg>='A')&&(*msg<='F')){
1877                 val=(*msg)-'A'+10;
1878             } else {
1879                 return;
1880             }
1881             val<<=4;
1882             msg++;
1883             if((*msg>='0')&&(*msg<='9')){
1884                 val|=(*msg)-'0';
1885             } else if((*msg>='a')&&(*msg<='f')){
1886                 val|=(*msg)-'a'+10;
1887             } else if((*msg>='A')&&(*msg<='F')){
1888                 val|=(*msg)-'A'+10;
1889             } else {
1890                 return;
1891             }
1892             msg++;
1893
1894             buf[i]=(guint8)val;
1895             i++;
1896         }
1897         if(i==0){
1898             return;
1899         }
1900         h245_tvb = tvb_new_child_real_data(tvb, buf,i,i);
1901         add_new_data_source(pinfo, h245_tvb, "H.245 over MEGACO");
1902         /* should go through a handle, however,  the two h245 entry
1903            points are different, one is over tpkt and the other is raw
1904         */
1905         call_dissector(h245_handle, h245_tvb, pinfo, top_tree);
1906 /*      dissect_h245_MultimediaSystemControlMessage(h245_tvb, pinfo, tree);*/
1907     }
1908 }
1909
1910 static void
1911 dissect_megaco_h324_h223caprn(tvbuff_t *tvb, packet_info *pinfo, proto_tree *megaco_tree, gint offset _U_, gint len, gchar *msg)
1912 {
1913     asn1_ctx_t actx;
1914
1915     /* arbitrary maximum length */
1916     if(len<20480){
1917         int i;
1918         tvbuff_t *h245_tvb;
1919         guint8 *buf = (guint8 *)wmem_alloc(pinfo->pool, 10240);
1920
1921         /* first, skip to where the encoded pdu starts, this is
1922            the first hex digit after the '=' char.
1923         */
1924         while(1){
1925             if((*msg==0)||(*msg=='\n')){
1926                 return;
1927             }
1928             if(*msg=='='){
1929                 msg++;
1930                 break;
1931             }
1932             msg++;
1933         }
1934         while(1){
1935             if((*msg==0)||(*msg=='\n')){
1936                 return;
1937             }
1938             if( ((*msg>='0')&&(*msg<='9'))
1939             ||  ((*msg>='a')&&(*msg<='f'))
1940             ||  ((*msg>='A')&&(*msg<='F'))){
1941                 break;
1942             }
1943             msg++;
1944         }
1945         i=0;
1946         while( ((*msg>='0')&&(*msg<='9'))
1947              ||((*msg>='a')&&(*msg<='f'))
1948              ||((*msg>='A')&&(*msg<='F'))  ){
1949             int val;
1950             if((*msg>='0')&&(*msg<='9')){
1951                 val=(*msg)-'0';
1952             } else if((*msg>='a')&&(*msg<='f')){
1953                 val=(*msg)-'a'+10;
1954             } else if((*msg>='A')&&(*msg<='F')){
1955                 val=(*msg)-'A'+10;
1956             } else {
1957                 return;
1958             }
1959             val<<=4;
1960             msg++;
1961             if((*msg>='0')&&(*msg<='9')){
1962                 val|=(*msg)-'0';
1963             } else if((*msg>='a')&&(*msg<='f')){
1964                 val|=(*msg)-'a'+10;
1965             } else if((*msg>='A')&&(*msg<='F')){
1966                 val|=(*msg)-'A'+10;
1967             } else {
1968                 return;
1969             }
1970             msg++;
1971
1972             buf[i]=(guint8)val;
1973             i++;
1974         }
1975         if(i==0){
1976             return;
1977         }
1978         h245_tvb = tvb_new_child_real_data(tvb, buf,i,i);
1979         add_new_data_source(pinfo, h245_tvb, "H.245 over MEGACO");
1980         /* should go through a handle, however,  the two h245 entry
1981            points are different, one is over tpkt and the other is raw
1982         */
1983         asn1_ctx_init(&actx, ASN1_ENC_PER, TRUE, pinfo);
1984         dissect_h245_H223Capability(h245_tvb, 0, &actx, megaco_tree, hf_megaco_h223Capability);
1985     }
1986 }
1987
1988 static void
1989 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)
1990 {
1991
1992     gint tokenlen, tvb_current_offset, tvb_next_offset, tvb_help_offset;
1993     gint tvb_events_end_offset, tvb_LBRKT;
1994     proto_tree  *megaco_eventsdescriptor_tree, *megaco_requestedevent_tree;
1995     proto_item  *megaco_eventsdescriptor_ti, *megaco_requestedevent_ti, *ti;
1996     guint8 tempchar;
1997
1998     gint requested_event_start_offset = 0,
1999          requested_event_end_offset = 0;
2000
2001     tokenlen =  (tvb_RBRKT+1) - tvb_previous_offset;
2002
2003     megaco_eventsdescriptor_ti = proto_tree_add_item(megaco_tree_command_line,hf_megaco_events_descriptor,tvb,tvb_previous_offset, tokenlen, ENC_NA);
2004     megaco_eventsdescriptor_tree = proto_item_add_subtree(megaco_eventsdescriptor_ti, ett_megaco_eventsdescriptor);
2005
2006     tvb_current_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_RBRKT, '=');
2007     tvb_next_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_RBRKT, '{');
2008
2009     if ( tvb_current_offset < tvb_RBRKT && tvb_current_offset != -1 ){
2010
2011         tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_current_offset +1);
2012         tvb_help_offset = megaco_tvb_skip_wsp_return(tvb, tvb_next_offset-1);
2013
2014         tokenlen =  tvb_help_offset - tvb_current_offset;
2015
2016         ti = proto_tree_add_uint(megaco_eventsdescriptor_tree, hf_megaco_requestid, tvb,
2017             tvb_current_offset, 1,
2018             (guint32) strtoul(tvb_format_text(tvb, tvb_current_offset, tokenlen), NULL, 10));
2019         proto_item_set_len(ti, tokenlen);
2020
2021         tvb_events_end_offset   = tvb_RBRKT;
2022
2023         tvb_RBRKT = tvb_next_offset+1;
2024         tvb_LBRKT = tvb_next_offset+1;
2025         tvb_previous_offset = megaco_tvb_skip_wsp(tvb, tvb_next_offset+1);
2026
2027
2028         do {
2029
2030             tvb_RBRKT = tvb_find_guint8(tvb, tvb_RBRKT+1,
2031                 tvb_events_end_offset, '}');
2032             tvb_LBRKT = tvb_find_guint8(tvb, tvb_LBRKT,
2033                 tvb_events_end_offset, '{');
2034
2035             tvb_current_offset  = tvb_find_guint8(tvb, tvb_previous_offset,
2036                 tvb_events_end_offset, ',');
2037
2038             if (tvb_current_offset == -1 || tvb_current_offset > tvb_events_end_offset){
2039                 tvb_current_offset = tvb_events_end_offset;
2040             }
2041
2042
2043             /* Descriptor includes no parameters */
2044
2045             if ( tvb_LBRKT > tvb_current_offset || tvb_LBRKT == -1 ){
2046
2047                 tvb_RBRKT = megaco_tvb_skip_wsp_return(tvb, tvb_current_offset-1)-1;
2048             }
2049
2050             /* Descriptor includes Parameters */
2051
2052             if ( (tvb_current_offset > tvb_LBRKT && tvb_LBRKT != -1)){
2053
2054                 while ( tvb_LBRKT != -1 && tvb_RBRKT > tvb_LBRKT ){
2055
2056                     tvb_LBRKT  = tvb_find_guint8(tvb, tvb_LBRKT+1,
2057                         tvb_events_end_offset, '{');
2058                     if ( tvb_LBRKT < tvb_RBRKT && tvb_LBRKT != -1)
2059                         tvb_RBRKT  = tvb_find_guint8(tvb, tvb_RBRKT+1,
2060                         tvb_events_end_offset, '}');
2061                 }
2062
2063             }
2064
2065             tvb_help_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_events_end_offset, '{');
2066
2067             /* if there are eventparameter  */
2068
2069             if ( tvb_help_offset < tvb_RBRKT && tvb_help_offset != -1 ){
2070
2071                 requested_event_start_offset = tvb_help_offset;
2072                 requested_event_end_offset   = tvb_RBRKT;
2073                 tvb_help_offset = megaco_tvb_skip_wsp_return(tvb, tvb_help_offset-1);
2074                 tokenlen = tvb_help_offset - tvb_previous_offset;
2075             }
2076             /* no parameters */
2077             else {
2078                 tokenlen = tvb_RBRKT+1 - tvb_previous_offset;
2079             }
2080
2081             megaco_requestedevent_ti = proto_tree_add_item(megaco_eventsdescriptor_tree,hf_megaco_pkgdname,tvb,tvb_previous_offset,tokenlen, ENC_UTF_8|ENC_NA);
2082             megaco_requestedevent_tree = proto_item_add_subtree(megaco_requestedevent_ti, ett_megaco_requestedevent);
2083
2084             if ( tvb_help_offset < tvb_RBRKT && tvb_help_offset != -1 ){
2085
2086                 tvb_help_offset = megaco_tvb_skip_wsp(tvb, requested_event_start_offset +1);
2087                 tempchar = tvb_get_guint8(tvb, tvb_help_offset);
2088
2089                 requested_event_start_offset = megaco_tvb_skip_wsp(tvb, requested_event_start_offset +1);
2090                 requested_event_end_offset = megaco_tvb_skip_wsp_return(tvb, requested_event_end_offset-1);
2091
2092                 if ( tempchar == 'D' || tempchar == 'd'){
2093                     dissect_megaco_digitmapdescriptor(tvb, megaco_requestedevent_tree, requested_event_end_offset, requested_event_start_offset);
2094                 }
2095                 else{
2096                     tokenlen =  requested_event_end_offset - requested_event_start_offset;
2097                     if(!tvb_strneql(tvb, requested_event_start_offset, "h245", 4)){
2098                         dissect_megaco_h245(tvb, pinfo, megaco_requestedevent_tree, requested_event_start_offset, tokenlen, top_tree);
2099                     } else {
2100                         proto_tree_add_format_text(megaco_requestedevent_tree, tvb, requested_event_start_offset, tokenlen);
2101                     }
2102                 }
2103
2104             }
2105
2106             tvb_previous_offset = tvb_current_offset;
2107             tvb_current_offset  = tvb_find_guint8(tvb, tvb_RBRKT,
2108                 tvb_events_end_offset, ',');
2109
2110             if (tvb_current_offset == -1 || tvb_current_offset > tvb_events_end_offset || tvb_current_offset < tvb_previous_offset ) {
2111                 tvb_current_offset = tvb_events_end_offset;
2112             }
2113
2114             tvb_previous_offset = megaco_tvb_skip_wsp(tvb, tvb_current_offset+1);
2115
2116             tvb_LBRKT = tvb_previous_offset;
2117             tvb_RBRKT = tvb_previous_offset;
2118
2119         } while ( tvb_current_offset < tvb_events_end_offset );
2120     }
2121 }
2122
2123 static void
2124 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)
2125 {
2126
2127     gint tokenlen, pkg_tokenlen, tvb_current_offset, tvb_next_offset, tvb_help_offset;
2128     gint tvb_signals_end_offset, tvb_signals_start_offset, tvb_LBRKT;
2129     proto_tree  *megaco_signalsdescriptor_tree, *megaco_requestedsignal_tree;
2130     proto_item  *megaco_signalsdescriptor_ti, *megaco_requestedsignal_ti;
2131
2132     gint requested_signal_start_offset = 0,
2133          requested_signal_end_offset = 0;
2134
2135     tvb_signals_end_offset   = tvb_RBRKT;
2136     tvb_signals_start_offset = tvb_previous_offset;
2137
2138     if(g_ascii_toupper(tvb_get_guint8(tvb, tvb_previous_offset+1))=='G')
2139       tokenlen = 2;                             /* token is compact text (SG) */
2140     else
2141       tokenlen = 7;                             /* token must be verbose text (Signals) */
2142
2143     tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_previous_offset+tokenlen);
2144
2145     if(tvb_get_guint8(tvb, tvb_current_offset)!='{') {          /* {} has been omitted */
2146
2147       megaco_signalsdescriptor_ti = proto_tree_add_item(megaco_tree_command_line, hf_megaco_signal_descriptor, tvb, tvb_signals_start_offset, tokenlen, ENC_NA);
2148       expert_add_info(pinfo, megaco_signalsdescriptor_ti, &ei_megaco_signal_descriptor);
2149
2150       col_append_str(pinfo->cinfo, COL_INFO, " (Signal:none)");     /* then say so */
2151
2152       return;                               /* and return */
2153     }
2154
2155     tvb_LBRKT = tvb_find_guint8(tvb, tvb_previous_offset, tvb_signals_end_offset, '{');
2156     tokenlen =  (tvb_LBRKT+1) - tvb_signals_start_offset;
2157
2158     megaco_signalsdescriptor_ti = proto_tree_add_item(megaco_tree_command_line,hf_megaco_signal_descriptor,tvb,tvb_previous_offset,tokenlen, ENC_NA);
2159     megaco_signalsdescriptor_tree = proto_item_add_subtree(megaco_signalsdescriptor_ti, ett_megaco_signalsdescriptor);
2160
2161     tvb_current_offset = tvb_LBRKT;
2162     tvb_next_offset = megaco_tvb_skip_wsp(tvb, tvb_current_offset+1);
2163     col_append_fstr(pinfo->cinfo, COL_INFO, " (Signal:%s)",tvb_format_text(tvb, tvb_current_offset,tokenlen-tvb_current_offset+tvb_previous_offset));
2164
2165
2166     if ( tvb_current_offset < tvb_signals_end_offset && tvb_current_offset != -1 && tvb_next_offset != tvb_signals_end_offset){
2167
2168
2169         tvb_RBRKT = tvb_next_offset+1;
2170         tvb_LBRKT = tvb_next_offset+1;
2171         tvb_previous_offset = tvb_next_offset;
2172
2173
2174         do {
2175
2176             tvb_RBRKT = tvb_find_guint8(tvb, tvb_RBRKT+1,
2177                 tvb_signals_end_offset, '}');
2178             tvb_LBRKT = tvb_find_guint8(tvb, tvb_LBRKT,
2179                 tvb_signals_end_offset, '{');
2180
2181             tvb_current_offset  = tvb_find_guint8(tvb, tvb_previous_offset,
2182                 tvb_signals_end_offset, ',');
2183
2184             if (tvb_current_offset == -1 || tvb_current_offset > tvb_signals_end_offset){
2185                 tvb_current_offset = tvb_signals_end_offset;
2186             }
2187
2188
2189             /* Descriptor includes no parameters */
2190
2191             if ( tvb_LBRKT > tvb_current_offset || tvb_LBRKT == -1 ){
2192
2193                 tvb_RBRKT = megaco_tvb_skip_wsp_return(tvb, tvb_current_offset-1)-1;
2194             }
2195
2196             /* Descriptor includes Parameters */
2197
2198             if ( (tvb_current_offset > tvb_LBRKT && tvb_LBRKT != -1)){
2199
2200                 while ( tvb_LBRKT != -1 && tvb_RBRKT > tvb_LBRKT ){
2201
2202                     tvb_LBRKT  = tvb_find_guint8(tvb, tvb_LBRKT+1,
2203                         tvb_signals_end_offset, '{');
2204                     if ( tvb_LBRKT < tvb_RBRKT && tvb_LBRKT != -1)
2205                         tvb_RBRKT  = tvb_find_guint8(tvb, tvb_RBRKT+1,
2206                         tvb_signals_end_offset, '}');
2207                 }
2208
2209             }
2210
2211             tvb_help_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_signals_end_offset, '{');
2212
2213             /* if there are signalparameter  */
2214
2215             if ( tvb_help_offset < tvb_RBRKT && tvb_help_offset != -1 ){
2216
2217                 requested_signal_start_offset = tvb_help_offset;
2218                 requested_signal_end_offset  = tvb_RBRKT;
2219                 tvb_help_offset = megaco_tvb_skip_wsp_return(tvb, tvb_help_offset-1);
2220                 pkg_tokenlen = tvb_help_offset - tvb_previous_offset;
2221             }
2222             /* no parameters */
2223             else {
2224                  pkg_tokenlen = tvb_RBRKT+1 - tvb_previous_offset;
2225              }
2226
2227             megaco_requestedsignal_ti = proto_tree_add_item(megaco_signalsdescriptor_tree,hf_megaco_pkgdname,tvb,tvb_previous_offset,pkg_tokenlen, ENC_UTF_8|ENC_NA);
2228             megaco_requestedsignal_tree = proto_item_add_subtree(megaco_requestedsignal_ti, ett_megaco_requestedsignal);
2229
2230             if ( tvb_help_offset < tvb_RBRKT && tvb_help_offset != -1 ){
2231                 requested_signal_start_offset = megaco_tvb_skip_wsp(tvb, requested_signal_start_offset +1);
2232                 requested_signal_end_offset = megaco_tvb_skip_wsp_return(tvb, requested_signal_end_offset-1);
2233
2234                 tokenlen =  requested_signal_end_offset - requested_signal_start_offset;
2235
2236                 if(!tvb_strneql(tvb, requested_signal_start_offset, "h245", 4)){
2237                     dissect_megaco_h245(tvb, pinfo,  megaco_requestedsignal_tree, requested_signal_start_offset, tokenlen, top_tree);
2238                 } else {
2239                     proto_tree_add_format_text( megaco_requestedsignal_tree, tvb, requested_signal_start_offset, tokenlen);
2240                 }
2241                 /* Print the trailing '}' (raw formatting removed) */
2242                 /* proto_tree_add_format_text( megaco_requestedsignal_tree, tvb, tvb_RBRKT, 1); */
2243             }
2244
2245             tvb_current_offset  = tvb_find_guint8(tvb, tvb_RBRKT,
2246                 tvb_signals_end_offset, ',');
2247
2248             if (tvb_current_offset == -1 || tvb_current_offset > tvb_signals_end_offset || tvb_current_offset < tvb_previous_offset){
2249                 tvb_current_offset = tvb_signals_end_offset;
2250             }
2251
2252             tvb_previous_offset = megaco_tvb_skip_wsp(tvb, tvb_current_offset+1);
2253
2254             tvb_LBRKT = tvb_previous_offset;
2255             tvb_RBRKT = tvb_previous_offset;
2256             /* Print the trailing '}' (raw formatting removed) */
2257             /* proto_tree_add_format_text(megaco_tree_command_line, tvb, tvb_signals_end_offset, 1); */
2258
2259         } while ( tvb_current_offset < tvb_signals_end_offset );
2260     }else{
2261         /* signals{} (raw formatting removed)
2262         proto_tree_add_format_text(megaco_tree_command_line, tvb, tvb_signals_end_offset, 1); */
2263     }
2264
2265
2266 }
2267
2268 /*
2269    auditDescriptor      = AuditToken LBRKT [ auditItem *(COMMA auditItem) ] RBRKT
2270
2271    auditItem            = ( MuxToken / ModemToken / MediaToken /
2272                            SignalsToken / EventBufferToken /
2273                            DigitMapToken / StatsToken / EventsToken /
2274                            ObservedEventsToken / PackagesToken )                     */
2275 static void
2276 dissect_megaco_auditdescriptor(tvbuff_t *tvb, proto_tree *megaco_tree, packet_info *pinfo _U_,  gint tvb_stop, gint tvb_offset)
2277 {
2278     gint        tokenlen, tvb_end, tvb_next, token_index;
2279     proto_tree  *megaco_auditdescriptor_tree, *megaco_auditdescriptor_ti;
2280
2281     tvb_next  = tvb_find_guint8(tvb, tvb_offset, tvb_stop, '{');           /* find opening LBRKT - is this already checked by caller?*/
2282     if( tvb_next == -1 )                                                   /* complain and give up if not there */
2283     {
2284         expert_add_info(pinfo, megaco_tree, &ei_megaco_audit_descriptor);
2285         return;
2286     }
2287     tokenlen = (tvb_stop + 1) - tvb_offset;
2288
2289     megaco_auditdescriptor_ti = proto_tree_add_item( megaco_tree, hf_megaco_audit_descriptor, tvb, tvb_offset, tokenlen, ENC_NA);
2290     megaco_auditdescriptor_tree = proto_item_add_subtree( megaco_auditdescriptor_ti, ett_megaco_auditdescriptor );
2291
2292     tvb_offset = tvb_next;
2293
2294     while( tvb_offset < tvb_stop )
2295     {
2296         tvb_offset = megaco_tvb_skip_wsp(tvb, tvb_offset+1);                                          /* find start of an auditItem */
2297         if( tvb_get_guint8(tvb, tvb_offset) != '}' )                                                  /* got something */
2298         {
2299             tvb_next = tvb_find_guint8(tvb, tvb_offset, tvb_stop, ',');                           /* end of an auditItem */
2300             if (tvb_next == -1)                                                                   /* last item doesn't have a comma */
2301                 tvb_next = tvb_stop;
2302             tvb_end = megaco_tvb_skip_wsp_return(tvb, tvb_next-1);                                /* trim any trailing whitespace */
2303             tokenlen =  tvb_end - tvb_offset;                                                     /* get length of token */
2304
2305             token_index = find_megaco_descriptors_names(tvb, tvb_offset, tokenlen);               /* lookup the token */
2306             if( token_index == -1 )                                                               /* if not found then 0 => Unknown */
2307                 token_index = 0;
2308
2309             proto_tree_add_string(megaco_auditdescriptor_tree, hf_megaco_audititem, tvb,
2310                     tvb_offset, tokenlen, megaco_descriptors_names[token_index].name);    /* and display the long form */
2311
2312             tvb_offset = tvb_next;                                                                /* advance pointer */
2313         }
2314     }
2315 }
2316
2317 /*
2318  *    serviceChangeDescriptor = ServicesToken LBRKT serviceChangeParm
2319  *                          *(COMMA serviceChangeParm) RBRKT
2320  *
2321  *    ServicesToken              = ("Services"              / "SV")
2322  *
2323  *    serviceChangeParm    = (serviceChangeMethod / serviceChangeReason /
2324  *                        serviceChangeDelay / serviceChangeAddress /
2325  *                       serviceChangeProfile / extension / TimeStamp /
2326  *                        serviceChangeMgcId / serviceChangeVersion )
2327  *
2328  */
2329 #define MEGACO_REASON_TOKEN     1
2330 #define MEGACO_DELAY_TOKEN      2
2331 #define MEGACO_SC_ADDR_TOKEN    3
2332 #define MEGACO_MGC_ID_TOKEN     4
2333 #define MEGACO_PROFILE_TOKEN    5
2334 #define MEGACO_VERSION_TOKEN    6
2335 #define MEGACO_METHOD_TOKEN     7
2336
2337 static const megaco_tokens_t megaco_serviceChangeParm_names[] = {
2338     { "Unknown-token",              NULL }, /* 0 Pad so that the real headers start at index 1 */
2339     /* streamMode */
2340     { "Reason",                     "RE" }, /* 1 ReasonToken*/
2341     { "Delay",                      "DL" }, /* 2 DelayToken */
2342     { "ServiceChangeAddress",       "AD" }, /* 3 ServiceChangeAddressToken */
2343     { "MgcIdToTry",                 "MG" }, /* 4 MgcIdToken */
2344     { "Profile",                    "PF" }, /* 5 ProfileToken */
2345     { "Version",                    "V"  }, /* 6 VersionToken */
2346     { "Method",                     "MT" }, /* 7  MethodToken */
2347 };
2348
2349 /* Returns index of megaco_tokens_t */
2350 static gint find_megaco_megaco_serviceChangeParm_names(tvbuff_t *tvb, int offset, guint header_len)
2351 {
2352     guint i;
2353
2354     for (i = 1; i < array_length(megaco_serviceChangeParm_names); i++) {
2355         if (header_len == strlen(megaco_serviceChangeParm_names[i].name) &&
2356             tvb_strncaseeql(tvb, offset, megaco_serviceChangeParm_names[i].name, header_len) == 0)
2357             return i;
2358         if (megaco_serviceChangeParm_names[i].compact_name != NULL &&
2359             header_len == strlen(megaco_serviceChangeParm_names[i].compact_name) &&
2360             tvb_strncaseeql(tvb, offset, megaco_serviceChangeParm_names[i].compact_name, header_len) == 0)
2361             return i;
2362     }
2363
2364     return -1;
2365 }
2366 /*
2367  * ServiceChangeReasons                                    References
2368  * --------------------                                    ----------
2369  */
2370 static const value_string MEGACO_ServiceChangeReasons_vals[] = {
2371     {900, "Service Restored"},
2372     {901, "Cold Boot"},
2373     {902, "Warm Boot"},
2374     {903, "MGC Directed Change"},
2375     {904, "Termination malfunctioning"},
2376     {905, "Termination taken out of service"},
2377     {906, "Loss of lower layer connectivity (e.g. downstream sync)"},
2378     {907, "Transmission Failure"},
2379     {908, "MG Impending Failure"},
2380     {909, "MGC Impending Failure"},
2381     {910, "Media Capability Failure"},
2382     {911, "Modem Capability Failure"},
2383     {912, "Mux Capability Failure"},
2384     {913, "Signal Capability Failure"},
2385     {914, "Event Capability Failure"},
2386     {915, "State Loss"},
2387     {916, "Packages Change"},
2388     {917, "Capabilities Change"},
2389     {918, "Cancel Graceful"},
2390     {919, "Warm Failover"},
2391     {920, "Cold Failover"},
2392     {  0, NULL }
2393 };
2394
2395 static void
2396 dissect_megaco_servicechangedescriptor(tvbuff_t *tvb, packet_info* pinfo, proto_tree *megaco_tree,  gint tvb_RBRKT,
2397     gint tvb_previous_offset)
2398 {
2399
2400     gint        tokenlen, tvb_LBRKT, tvb_offset;
2401     gint        token_index;
2402     gint        tvb_current_offset;
2403     gboolean    more_params = TRUE;
2404     proto_item* item;
2405     gint                reason;
2406     gboolean            reason_valid;
2407     guint8              ServiceChangeReason_str[4];
2408
2409     tvb_LBRKT  = tvb_find_guint8(tvb, tvb_previous_offset, tvb_RBRKT, '{');
2410     /*
2411     if (tvb_LBRKT == -1)
2412         return;
2413         */
2414     tokenlen = (tvb_LBRKT + 1) - tvb_previous_offset;
2415     proto_tree_add_format_text(megaco_tree, tvb, tvb_previous_offset, tokenlen);
2416
2417     /* Start dissecting serviceChangeParm */
2418     tvb_previous_offset = tvb_LBRKT + 1;
2419     while (more_params){
2420         tvb_previous_offset = megaco_tvb_skip_wsp(tvb, tvb_previous_offset);
2421         /* Find token length */
2422         for (tvb_offset=tvb_previous_offset; tvb_offset < tvb_RBRKT; tvb_offset++){
2423             if (!g_ascii_isalpha(tvb_get_guint8(tvb, tvb_offset ))){
2424                 break;
2425             }
2426         }
2427         tokenlen = tvb_offset - tvb_previous_offset;
2428         token_index = find_megaco_megaco_serviceChangeParm_names(tvb, tvb_previous_offset, tokenlen);
2429
2430         tvb_offset  = tvb_find_guint8(tvb, tvb_offset, tvb_RBRKT, ',');
2431         if ((tvb_offset == -1)||(tvb_offset >=tvb_RBRKT)){
2432             more_params = FALSE;
2433             tvb_offset = megaco_tvb_skip_wsp_return(tvb, tvb_RBRKT-1);
2434         }
2435         tokenlen = tvb_offset - tvb_previous_offset;
2436         if (more_params == TRUE )
2437             /* Include ',' */
2438             tokenlen++;
2439         switch(token_index){
2440         case MEGACO_REASON_TOKEN:
2441             /* ReasonToken  EQUAL VALUE
2442              * VALUE                = quotedString / 1*(SafeChar)
2443              */
2444             item = proto_tree_add_format_text(megaco_tree, tvb, tvb_previous_offset, tokenlen);
2445
2446             /* As the reason code ( if a digit ) can be in quoted string or 'just' digit
2447              * look for a nine and hope for the best.
2448              */
2449             tvb_current_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_RBRKT, '9');
2450             if ( tvb_current_offset == -1)
2451                 break;
2452
2453             tvb_get_nstringz0(tvb,tvb_current_offset,4,ServiceChangeReason_str);
2454             reason_valid = ws_strtoi32(ServiceChangeReason_str, NULL, &reason);
2455             proto_item_append_text(item,"[ %s ]", val_to_str(reason, MEGACO_ServiceChangeReasons_vals,"Unknown (%u)"));
2456             if (!reason_valid)
2457                 expert_add_info(pinfo, item, &ei_megaco_reason_invalid);
2458             break;
2459         case MEGACO_DELAY_TOKEN:
2460         case MEGACO_SC_ADDR_TOKEN:
2461         case MEGACO_MGC_ID_TOKEN:
2462         case MEGACO_PROFILE_TOKEN:
2463         case MEGACO_VERSION_TOKEN:
2464         case MEGACO_METHOD_TOKEN:
2465             /* No special dissection: fall through */
2466         default:
2467         /* Unknown or:
2468          * extension            = extensionParameter parmValue
2469          * extensionParameter   = "X"  ("-" / "+") 1*6(ALPHA / DIGIT)
2470          */
2471             proto_tree_add_format_text(megaco_tree, tvb, tvb_previous_offset, tokenlen);
2472             break;
2473         }
2474
2475         tvb_previous_offset = tvb_offset +1;
2476
2477     }/*End while */
2478
2479     /* extension            = extensionParameter parmValue
2480      * extensionParameter   = "X"  ("-" / "+") 1*6(ALPHA / DIGIT)
2481      */
2482
2483      /*
2484     tokenlen =  (tvb_RBRKT+1) - tvb_previous_offset;
2485     proto_tree_add_string(megaco_tree_command_line, hf_megaco_servicechange_descriptor, tvb,
2486                             tvb_previous_offset, tokenlen,
2487                             tvb_format_text(tvb, tvb_previous_offset,
2488                             tokenlen));
2489     */
2490     proto_tree_add_format_text(megaco_tree, tvb, tvb_RBRKT, 1);
2491
2492 }
2493 static void
2494 dissect_megaco_digitmapdescriptor(tvbuff_t *tvb, proto_tree *megaco_tree_command_line,  gint tvb_RBRKT, gint tvb_previous_offset)
2495 {
2496
2497     gint    tokenlen;
2498
2499     tokenlen =  tvb_RBRKT - tvb_previous_offset;
2500     proto_tree_add_string(megaco_tree_command_line, hf_megaco_digitmap_descriptor, tvb,
2501                             tvb_previous_offset, tokenlen,
2502                             tvb_format_text(tvb, tvb_previous_offset,
2503                             tokenlen));
2504
2505 }
2506 static void
2507 dissect_megaco_statisticsdescriptor(tvbuff_t *tvb, proto_tree *megaco_tree_command_line,  gint tvb_RBRKT, gint tvb_previous_offset)
2508 {
2509     gint    tokenlen;
2510     proto_tree  *megaco_statisticsdescriptor_tree;
2511     proto_item  *megaco_statisticsdescriptor_ti;
2512     gint tvb_help_offset, param_start_offset, param_end_offset = 0;
2513
2514     tokenlen =  (tvb_RBRKT+1) - tvb_previous_offset;
2515
2516     megaco_statisticsdescriptor_ti = proto_tree_add_item(megaco_tree_command_line,hf_megaco_statistics_descriptor,tvb,tvb_previous_offset,tokenlen, ENC_NA);
2517     megaco_statisticsdescriptor_tree = proto_item_add_subtree(megaco_statisticsdescriptor_ti, ett_megaco_statisticsdescriptor);
2518
2519     tvb_help_offset = tvb_find_guint8(tvb, tvb_previous_offset+1, tvb_RBRKT, '{');
2520     do {
2521         param_start_offset = megaco_tvb_skip_wsp(tvb, tvb_help_offset+1);
2522
2523         tvb_help_offset = tvb_find_guint8(tvb, tvb_help_offset+1, tvb_RBRKT, ',');
2524
2525         if ( tvb_help_offset > tvb_RBRKT || tvb_help_offset == -1){
2526             tvb_help_offset = tvb_RBRKT;
2527             param_end_offset = megaco_tvb_skip_wsp_return(tvb, tvb_RBRKT-1);
2528             tokenlen =  param_end_offset - param_start_offset;
2529         } else {
2530             param_end_offset = megaco_tvb_skip_wsp(tvb, tvb_help_offset-1);
2531             tokenlen =  param_end_offset - param_start_offset+1;
2532         }
2533
2534         proto_tree_add_format_text(megaco_statisticsdescriptor_tree, tvb,param_start_offset, tokenlen);
2535
2536     } while ( tvb_help_offset < tvb_RBRKT );
2537 }
2538
2539 static void
2540 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)
2541 {
2542
2543     gint tokenlen, pkg_tokenlen, tvb_current_offset, tvb_next_offset, tvb_help_offset;
2544     gint tvb_observedevents_end_offset, tvb_LBRKT;
2545     proto_tree  *megaco_observedeventsdescriptor_tree, *megaco_observedevent_tree;
2546     proto_item  *megaco_observedeventsdescriptor_ti, *megaco_observedevent_ti, *ti;
2547
2548     gint requested_event_start_offset, requested_event_end_offset, param_start_offset, param_end_offset;
2549
2550     requested_event_start_offset    = 0;
2551     requested_event_end_offset  = 0;
2552
2553     tvb_LBRKT = tvb_find_guint8(tvb, tvb_previous_offset, tvb_RBRKT, '{');
2554     tvb_next_offset = tvb_LBRKT;
2555     tokenlen =  (tvb_next_offset+1) - tvb_previous_offset;
2556
2557     megaco_observedeventsdescriptor_ti = proto_tree_add_item(megaco_tree_command_line,hf_megaco_observedevents_descriptor,tvb,tvb_previous_offset,tokenlen, ENC_NA);
2558     megaco_observedeventsdescriptor_tree = proto_item_add_subtree(megaco_observedeventsdescriptor_ti, ett_megaco_observedeventsdescriptor);
2559
2560     tvb_current_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_RBRKT, '=');
2561     tvb_next_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_RBRKT, '{');
2562
2563     if ( tvb_current_offset < tvb_RBRKT && tvb_current_offset != -1 ){
2564
2565         tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_current_offset +1);
2566         tvb_help_offset = megaco_tvb_skip_wsp_return(tvb, tvb_next_offset-1);
2567
2568         tokenlen =  tvb_help_offset - tvb_current_offset;
2569
2570         ti = proto_tree_add_uint(megaco_observedeventsdescriptor_tree, hf_megaco_requestid, tvb,
2571             tvb_current_offset, 1,
2572             (guint32) strtoul(tvb_format_text(tvb, tvb_current_offset, tokenlen), NULL, 10));
2573         proto_item_set_len(ti, tokenlen);
2574
2575         tvb_observedevents_end_offset   = tvb_RBRKT;
2576
2577         tvb_RBRKT = tvb_next_offset+1;
2578         tvb_LBRKT = tvb_next_offset+1;
2579         tvb_previous_offset = megaco_tvb_skip_wsp(tvb, tvb_next_offset+1);
2580
2581
2582         do {
2583
2584             tvb_RBRKT = tvb_find_guint8(tvb, tvb_RBRKT+1,
2585                 tvb_observedevents_end_offset, '}');
2586             tvb_LBRKT = tvb_find_guint8(tvb, tvb_LBRKT,
2587                 tvb_observedevents_end_offset, '{');
2588
2589             tvb_current_offset  = tvb_find_guint8(tvb, tvb_previous_offset,
2590                 tvb_observedevents_end_offset, ',');
2591
2592             if (tvb_current_offset == -1 || tvb_current_offset > tvb_observedevents_end_offset){
2593                 tvb_current_offset = tvb_observedevents_end_offset;
2594             }
2595
2596
2597             /* Descriptor includes no parameters */
2598
2599             if ( tvb_LBRKT > tvb_current_offset || tvb_LBRKT == -1 ){
2600
2601                 tvb_RBRKT = megaco_tvb_skip_wsp_return(tvb, tvb_current_offset-1)-1;
2602             }
2603
2604             /* Descriptor includes Parameters */
2605
2606             if ( (tvb_current_offset > tvb_LBRKT && tvb_LBRKT != -1)){
2607
2608                 while ( tvb_LBRKT != -1 && tvb_RBRKT > tvb_LBRKT ){
2609
2610                     tvb_LBRKT  = tvb_find_guint8(tvb, tvb_LBRKT+1,
2611                         tvb_observedevents_end_offset, '{');
2612                     if ( tvb_LBRKT < tvb_RBRKT && tvb_LBRKT != -1){
2613                         tvb_RBRKT  = tvb_find_guint8(tvb, tvb_RBRKT+1,
2614                             tvb_observedevents_end_offset, '}');
2615                     }
2616                 }
2617
2618             }
2619
2620             tvb_LBRKT = tvb_help_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_observedevents_end_offset, '{');
2621
2622             /* if there are eventparameter  */
2623
2624             if ( tvb_help_offset < tvb_RBRKT && tvb_help_offset != -1 ){
2625
2626                 requested_event_start_offset = tvb_help_offset;
2627                 requested_event_end_offset   = tvb_RBRKT;
2628                 tvb_help_offset = megaco_tvb_skip_wsp_return(tvb, tvb_help_offset-1);
2629                 pkg_tokenlen = tvb_help_offset - tvb_previous_offset;
2630                 tokenlen = tvb_LBRKT+1 - tvb_previous_offset;
2631             }
2632             /* no parameters */
2633             else {
2634                 tokenlen = pkg_tokenlen = tvb_RBRKT+1 - tvb_previous_offset;
2635             }
2636
2637             megaco_observedevent_ti = proto_tree_add_format_text(megaco_tree_command_line, tvb, tvb_previous_offset, tokenlen);
2638
2639             megaco_observedevent_tree = proto_item_add_subtree(megaco_observedevent_ti, ett_megaco_observedevent);
2640
2641             proto_tree_add_item(megaco_observedevent_tree,hf_megaco_pkgdname,tvb,tvb_previous_offset,pkg_tokenlen, ENC_UTF_8|ENC_NA);
2642
2643             if ( tvb_help_offset < tvb_RBRKT && tvb_help_offset != -1 ){
2644
2645                 requested_event_start_offset = megaco_tvb_skip_wsp(tvb, requested_event_start_offset +1)-1;
2646                 requested_event_end_offset = megaco_tvb_skip_wsp_return(tvb, requested_event_end_offset-1);
2647
2648                 tvb_help_offset = requested_event_start_offset;
2649
2650                 do {
2651                     param_start_offset = megaco_tvb_skip_wsp(tvb, tvb_help_offset+1);
2652
2653                     tvb_help_offset = tvb_find_guint8(tvb, tvb_help_offset+1,requested_event_end_offset, ',');
2654
2655                     if ( tvb_help_offset > requested_event_end_offset || tvb_help_offset == -1){
2656                         tvb_help_offset = requested_event_end_offset;
2657                     }
2658
2659                     param_end_offset = megaco_tvb_skip_wsp(tvb, tvb_help_offset-1);
2660
2661                     tokenlen =  param_end_offset - param_start_offset+1;
2662                     if(!tvb_strneql(tvb, param_start_offset, "h245", 4)){
2663                         dissect_megaco_h245(tvb, pinfo, megaco_tree_command_line, param_start_offset, tokenlen, top_tree);
2664                     } else {
2665                         proto_tree_add_format_text(megaco_tree_command_line, tvb, param_start_offset, tokenlen);
2666                     }
2667
2668
2669                 } while ( tvb_help_offset < requested_event_end_offset );
2670             }
2671
2672             tvb_previous_offset = tvb_current_offset;
2673             tvb_current_offset  = tvb_find_guint8(tvb, tvb_RBRKT,
2674                 tvb_observedevents_end_offset, ',');
2675
2676             if (tvb_current_offset == -1 || tvb_current_offset > tvb_observedevents_end_offset ){
2677                 tvb_current_offset = tvb_observedevents_end_offset;
2678             }
2679             if (tvb_current_offset < tvb_previous_offset) {
2680                 expert_add_info_format(pinfo, megaco_observedevent_ti, &ei_megaco_parse_error, "Parse error: Invalid offset");
2681                 return;
2682             }
2683
2684             tvb_previous_offset = megaco_tvb_skip_wsp(tvb, tvb_current_offset+1);
2685
2686             tvb_LBRKT = tvb_previous_offset;
2687             tvb_RBRKT = tvb_previous_offset;
2688             /* Print the trailing '}' (raw formatting removed) */
2689             /* proto_tree_add_format_text(megaco_tree_command_line, tvb, tvb_observedevents_end_offset, 1); */
2690
2691         } while ( tvb_current_offset < tvb_observedevents_end_offset );
2692     }
2693 }
2694 static void
2695 dissect_megaco_topologydescriptor(tvbuff_t *tvb, proto_tree *megaco_tree_command_line,  gint tvb_RBRKT, gint tvb_previous_offset)
2696 {
2697
2698     gint    tokenlen;
2699
2700     tokenlen =  (tvb_RBRKT+1) - tvb_previous_offset;
2701     proto_tree_add_string(megaco_tree_command_line, hf_megaco_topology_descriptor, tvb,
2702                             tvb_previous_offset, tokenlen,
2703                             tvb_format_text_wsp(wmem_packet_scope(), tvb, tvb_previous_offset,
2704                             tokenlen));
2705
2706 }
2707 static void
2708 dissect_megaco_Packagesdescriptor(tvbuff_t *tvb, proto_tree *megaco_tree_command_line,  gint tvb_RBRKT, gint tvb_previous_offset)
2709 {
2710
2711     gint tokenlen, tvb_current_offset, tvb_next_offset, tvb_help_offset;
2712     gint tvb_packages_end_offset, tvb_LBRKT;
2713     proto_tree  *megaco_packagesdescriptor_tree;
2714     proto_item  *megaco_packagesdescriptor_ti, *ti;
2715
2716     tokenlen =  (tvb_RBRKT+1) - tvb_previous_offset;
2717
2718     megaco_packagesdescriptor_ti = proto_tree_add_item(megaco_tree_command_line,hf_megaco_packages_descriptor,tvb,tvb_previous_offset,tokenlen, ENC_UTF_8|ENC_NA);
2719     megaco_packagesdescriptor_tree = proto_item_add_subtree(megaco_packagesdescriptor_ti, ett_megaco_packagesdescriptor);
2720
2721     tvb_current_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_RBRKT, '=');
2722     tvb_next_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_RBRKT, '{');
2723
2724     if ( tvb_current_offset < tvb_RBRKT && tvb_current_offset != -1 ){
2725
2726         tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_current_offset +1);
2727         tvb_help_offset = megaco_tvb_skip_wsp_return(tvb, tvb_next_offset-1);
2728
2729         tokenlen =  tvb_help_offset - tvb_current_offset;
2730
2731         ti = proto_tree_add_uint(megaco_packagesdescriptor_tree, hf_megaco_requestid, tvb,
2732             tvb_current_offset, 1,
2733             (guint32) strtoul(tvb_format_text(tvb, tvb_current_offset, tokenlen), NULL, 10));
2734         proto_item_set_len(ti, tokenlen);
2735
2736         tvb_packages_end_offset   = tvb_RBRKT;
2737
2738         tvb_RBRKT = tvb_next_offset+1;
2739         tvb_LBRKT = tvb_next_offset+1;
2740         tvb_previous_offset = megaco_tvb_skip_wsp(tvb, tvb_next_offset+1);
2741
2742
2743         do {
2744
2745             tvb_RBRKT = tvb_find_guint8(tvb, tvb_RBRKT+1,
2746                 tvb_packages_end_offset, '}');
2747             tvb_LBRKT = tvb_find_guint8(tvb, tvb_LBRKT,
2748                 tvb_packages_end_offset, '{');
2749
2750             tvb_current_offset  = tvb_find_guint8(tvb, tvb_previous_offset,
2751                 tvb_packages_end_offset, ',');
2752
2753             if (tvb_current_offset == -1 || tvb_current_offset > tvb_packages_end_offset){
2754                 tvb_current_offset = tvb_packages_end_offset;
2755             }
2756
2757
2758             /* Descriptor includes no parameters */
2759
2760             if ( tvb_LBRKT > tvb_current_offset || tvb_LBRKT == -1 ){
2761
2762                 tvb_RBRKT = megaco_tvb_skip_wsp_return(tvb, tvb_current_offset-1)-1;
2763             }
2764
2765             /* Descriptor includes Parameters */
2766
2767             if ( (tvb_current_offset > tvb_LBRKT && tvb_LBRKT != -1)){
2768
2769                 while ( tvb_LBRKT != -1 && tvb_RBRKT > tvb_LBRKT ){
2770
2771                     tvb_LBRKT  = tvb_find_guint8(tvb, tvb_LBRKT+1,
2772                         tvb_packages_end_offset, '{');
2773                     if ( tvb_LBRKT < tvb_RBRKT && tvb_LBRKT != -1)
2774                         tvb_RBRKT  = tvb_find_guint8(tvb, tvb_RBRKT+1,
2775                         tvb_packages_end_offset, '}');
2776                 }
2777
2778             }
2779
2780             tokenlen = tvb_RBRKT+1 - tvb_previous_offset;
2781
2782             proto_tree_add_format_text(megaco_packagesdescriptor_tree, tvb, tvb_previous_offset, tokenlen);
2783
2784             tvb_current_offset      = tvb_find_guint8(tvb, tvb_RBRKT,
2785                 tvb_packages_end_offset, ',');
2786
2787             if (tvb_current_offset == -1 || tvb_current_offset > tvb_packages_end_offset ){
2788                 tvb_current_offset = tvb_packages_end_offset;
2789             }
2790
2791             tvb_previous_offset = megaco_tvb_skip_wsp(tvb, tvb_current_offset+1);
2792
2793             tvb_LBRKT = tvb_previous_offset;
2794             tvb_RBRKT = tvb_previous_offset;
2795
2796         } while ( tvb_current_offset < tvb_packages_end_offset );
2797     }
2798
2799 }
2800 /* The list of error code values is fetched from http://www.iana.org/assignments/megaco-h248    */
2801 /* 2003-08-28                                           */
2802
2803 static const value_string MEGACO_error_code_vals[] = {
2804
2805     {400, "Syntax error in message"},
2806     {401, "Protocol Error"},
2807     {402, "Unauthorized"},
2808     {403, "Syntax error in transaction request"},
2809     {406, "Version Not Supported"},
2810     {410, "Incorrect identifier"},
2811     {411, "The transaction refers to an unknown ContextId"},
2812     {412, "No ContextIDs available"},
2813     {421, "Unknown action or illegal combination of actions"},
2814     {422, "Syntax Error in Action"},
2815     {430, "Unknown TerminationID"},
2816     {431, "No TerminationID matched a wildcard"},
2817     {432, "Out of TerminationIDs or No TerminationID available"},
2818     {433, "TerminationID is already in a Context"},
2819     {434, "Max number of Terminations in a Context exceeded"},
2820     {435, "Termination ID is not in specified Context"},
2821     {440, "Unsupported or unknown Package"},
2822     {441, "Missing Remote or Local Descriptor"},
2823     {442, "Syntax Error in Command"},
2824     {443, "Unsupported or Unknown Command"},
2825     {444, "Unsupported or Unknown Descriptor"},
2826     {445, "Unsupported or Unknown Property"},
2827     {446, "Unsupported or Unknown Parameter"},
2828     {447, "Descriptor not legal in this command"},
2829     {448, "Descriptor appears twice in a command"},
2830     {450, "No such property in this package"},
2831     {451, "No such event in this package"},
2832     {452, "No such signal in this package"},
2833     {453, "No such statistic in this package"},
2834     {454, "No such parameter value in this package"},
2835     {455, "Property illegal in this Descriptor"},
2836     {456, "Property appears twice in this Descriptor"},
2837     {457, "Missing parameter in signal or event"},
2838     {458, "Unexpected Event/Request ID"},
2839     {459, "Unsupported or Unknown Profile"},
2840     {471, "Implied Add for Multiplex failure"},
2841
2842     {500, "Internal software Failure in MG"},
2843     {501, "Not Implemented"},
2844     {502, "Not ready."},
2845     {503, "Service Unavailable"},
2846     {504, "Command Received from unauthorized entity"},
2847     {505, "Transaction Request Received before a Service Change Reply has been received"},
2848     {506, "Number of Transaction Pendings Exceeded"},
2849     {510, "Insufficient resources"},
2850     {512, "Media Gateway unequipped to detect requested Event"},
2851     {513, "Media Gateway unequipped to generate requested Signals"},
2852     {514, "Media Gateway cannot send the specified announcement"},
2853     {515, "Unsupported Media Type"},
2854     {517, "Unsupported or invalid mode"},
2855     {518, "Event buffer full"},
2856     {519, "Out of space to store digit map"},
2857     {520, "Digit Map undefined in the MG"},
2858     {521, "Termination is ServiceChanging"},
2859     {526, "Insufficient bandwidth"},
2860     {529, "Internal hardware failure in MG"},
2861     {530, "Temporary Network failure"},
2862     {531, "Permanent Network failure"},
2863     {532, "Audited Property, Statistic, Event or Signal does not exist"},
2864     {533, "Response exceeds maximum transport PDU size"},
2865     {534, "Illegal write or read only property"},
2866     {540, "Unexpected initial hook state"},
2867     {581, "Does Not Exist"},
2868
2869     {600, "Illegal syntax within an announcement specification"},
2870     {601, "Variable type not supported"},
2871     {602, "Variable value out of range"},
2872     {603, "Category not supported"},
2873     {604, "Selector type not supported"},
2874     {605, "Selector value not supported"},
2875     {606, "Unknown segment ID"},
2876     {607, "Mismatch between play specification and provisioned data"},
2877     {608, "Provisioning error"},
2878     {609, "Invalid offset"},
2879     {610, "No free segment IDs"},
2880     {611, "Temporary segment not found"},
2881     {612, "Segment in use"},
2882     {613, "ISP port limit overrun"},
2883     {614, "No modems available"},
2884     {615, "Calling number unacceptable"},
2885     {616, "Called number unacceptable"},
2886     {  0, NULL }
2887 };
2888
2889
2890
2891 static void
2892 dissect_megaco_errordescriptor(tvbuff_t *tvb, packet_info* pinfo, proto_tree *megaco_tree_command_line,
2893     gint tvb_RBRKT, gint tvb_previous_offset)
2894 {
2895
2896     gint                tokenlen;
2897     gint                error_code;
2898     guint8              error[4];
2899     gint                tvb_current_offset;
2900     proto_item*         item;
2901     proto_tree*         error_tree;
2902     gboolean            error_code_valid;
2903
2904     tvb_current_offset = tvb_find_guint8(tvb, tvb_previous_offset , tvb_RBRKT, '=');
2905     tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_current_offset +1);
2906
2907     tokenlen =  (tvb_RBRKT) - tvb_previous_offset+1;
2908
2909     item = proto_tree_add_item(megaco_tree_command_line, hf_megaco_error_descriptor, tvb,
2910                             tvb_previous_offset, tokenlen, ENC_NA);
2911     error_tree = proto_item_add_subtree(item, ett_megaco_error_descriptor);
2912
2913     /* Get the error code */
2914     tvb_get_nstringz0(tvb,tvb_current_offset,4,error);
2915     error_code_valid = ws_strtoi32(error, NULL, &error_code);
2916     item = proto_tree_add_uint(error_tree, hf_megaco_error_code, tvb, tvb_current_offset, 3, error_code);
2917     if (!error_code_valid)
2918         expert_add_info(pinfo, item, &ei_megaco_error_code_invalid);
2919
2920     /* Get the error string (even though we have a value_string that should match) */
2921     tvb_previous_offset = tvb_find_guint8(tvb, tvb_current_offset, tvb_RBRKT, '\"');
2922     tvb_current_offset = tvb_find_guint8(tvb, tvb_previous_offset+1, tvb_RBRKT, '\"');
2923
2924     tokenlen =  tvb_current_offset - tvb_previous_offset-1;
2925     proto_tree_add_item(error_tree, hf_megaco_error_string, tvb, tvb_previous_offset+1, tokenlen, ENC_UTF_8|ENC_NA);
2926 }
2927 static void
2928 dissect_megaco_TerminationStatedescriptor(tvbuff_t *tvb, proto_tree *megaco_mediadescriptor_tree,  gint tvb_next_offset, gint tvb_current_offset)
2929 {
2930     gint tokenlen;
2931     gint tvb_offset;
2932     guint8 tempchar;
2933
2934     proto_tree  *megaco_TerminationState_tree, *megaco_TerminationState_ti;
2935
2936     tvb_offset = tvb_find_guint8(tvb, tvb_current_offset , tvb_next_offset, '=');
2937
2938     tokenlen = tvb_next_offset - tvb_current_offset;
2939     megaco_TerminationState_ti = proto_tree_add_item(megaco_mediadescriptor_tree,hf_megaco_TerminationState_descriptor,tvb,tvb_current_offset,tokenlen, ENC_NA);
2940     megaco_TerminationState_tree = proto_item_add_subtree(megaco_TerminationState_ti, ett_megaco_TerminationState);
2941
2942     while ( tvb_offset < tvb_next_offset && tvb_offset != -1 ){
2943
2944         tempchar = tvb_get_guint8(tvb, tvb_current_offset);
2945         tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
2946         if ( (tempchar >= 'a')&& (tempchar <= 'z'))
2947             tempchar = tempchar - 0x20;
2948
2949         switch ( tempchar ){
2950
2951         case 'S':
2952             tvb_offset = tvb_find_guint8(tvb, tvb_current_offset , tvb_offset, ',');
2953             if ( tvb_offset == -1 || tvb_offset > tvb_next_offset ){
2954                 tvb_offset = tvb_next_offset;
2955             }
2956
2957             tokenlen = tvb_offset - tvb_current_offset;
2958
2959             proto_tree_add_string(megaco_TerminationState_tree, hf_megaco_Service_State, tvb,
2960                 tvb_current_offset, tokenlen,
2961                 tvb_format_text(tvb, tvb_current_offset,
2962                 tokenlen));
2963
2964             break;
2965
2966         case 'B':
2967
2968             tvb_offset = tvb_find_guint8(tvb, tvb_current_offset , tvb_offset, ',');
2969             if ( tvb_offset == -1 || tvb_offset > tvb_next_offset ){
2970                 tvb_offset = tvb_next_offset;
2971             }
2972
2973             tokenlen = tvb_offset - tvb_current_offset;
2974
2975             proto_tree_add_string(megaco_TerminationState_tree, hf_megaco_Event_Buffer_Control, tvb,
2976                 tvb_current_offset, tokenlen,
2977                 tvb_format_text(tvb, tvb_current_offset,
2978                 tokenlen));
2979
2980             break;
2981
2982         case 'E':
2983             tvb_offset = tvb_find_guint8(tvb, tvb_current_offset , tvb_offset, ',');
2984             if ( tvb_offset == -1 || tvb_offset > tvb_next_offset ){
2985                 tvb_offset = tvb_next_offset;
2986             }
2987
2988             tokenlen = tvb_offset - tvb_current_offset;
2989
2990             proto_tree_add_string(megaco_TerminationState_tree, hf_megaco_Event_Buffer_Control, tvb,
2991                 tvb_current_offset, tokenlen,
2992                 tvb_format_text(tvb, tvb_current_offset,
2993                 tokenlen));
2994
2995             break;
2996
2997         default:
2998             tvb_offset = tvb_find_guint8(tvb, tvb_current_offset , tvb_offset, ',');
2999             if ( tvb_offset == -1 || tvb_offset > tvb_next_offset ){
3000                 tvb_offset = tvb_next_offset;
3001             }
3002
3003             tokenlen = tvb_offset - tvb_current_offset;
3004
3005             proto_tree_add_format_text(megaco_TerminationState_tree, tvb, tvb_current_offset, tokenlen);
3006             break;
3007         }
3008
3009
3010         tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
3011         tvb_offset = tvb_find_guint8(tvb, tvb_current_offset , tvb_next_offset, '=');
3012
3013     }
3014     /* (raw formatting removed)
3015     proto_tree_add_format_text(megaco_mediadescriptor_tree, tvb, tvb_next_offset, 1); */
3016 }
3017
3018 static void
3019 dissect_megaco_Localdescriptor(tvbuff_t *tvb, proto_tree *megaco_mediadescriptor_tree,packet_info *pinfo, gint tvb_next_offset, gint tvb_current_offset)
3020 {
3021     gint tokenlen;
3022     tvbuff_t *next_tvb;
3023
3024     proto_tree  *megaco_localdescriptor_tree;
3025     proto_item  *megaco_localdescriptor_item;
3026
3027     tokenlen = tvb_next_offset - tvb_current_offset;
3028
3029     megaco_localdescriptor_item = proto_tree_add_item(megaco_mediadescriptor_tree, hf_megaco_Local_descriptor, tvb, tvb_current_offset, tokenlen, ENC_NA);
3030     megaco_localdescriptor_tree = proto_item_add_subtree(megaco_localdescriptor_item, ett_megaco_Localdescriptor);
3031
3032     if ( tokenlen > 3 ){
3033         next_tvb = tvb_new_subset_length(tvb, tvb_current_offset, tokenlen);
3034         call_dissector(sdp_handle, next_tvb, pinfo, megaco_localdescriptor_tree);
3035     }
3036 }
3037
3038 /*
3039  *   localControlDescriptor = LocalControlToken LBRKT localParm
3040  *                          *(COMMA localParm) RBRKT
3041  *   ; at-most-once per item
3042  *   localParm            = ( streamMode / propertyParm / reservedValueMode / reservedGroupMode )
3043  */
3044
3045 #define MEGACO_MODETOKEN            1
3046 #define MEGACO_RESERVEDVALUETOKEN   2
3047 #define MEGACO_RESERVEDGROUPTOKEN   3
3048 #define MEGACO_H324_H223CAPR        4
3049 #define MEGACO_H324_MUXTBL_IN       5
3050 #define MEGACO_H324_MUXTBL_OUT      6
3051 #define MEGACO_DS_DSCP              7
3052 #define MEGACO_GM_SAF               8
3053 #define MEGACO_GM_SAM               9
3054 #define MEGACO_GM_SPF               10
3055 #define MEGACO_GM_SPR               11
3056 #define MEGACO_GM_ESAS              12
3057 #define MEGACO_GM_LSA               13
3058 #define MEGACO_GM_ESPS              14
3059 #define MEGACO_GM_LSP               15
3060 #define MEGACO_GM_RSB               16
3061 #define MEGACO_TMAN_POL             17
3062 #define MEGACO_TMAN_SDR             18
3063 #define MEGACO_TMAN_MBS             19
3064 #define MEGACO_TMAN_PDR             20
3065 #define MEGACO_TMAN_DVT             21
3066 #define MEGACO_IPDC_REALM           22
3067
3068 static const megaco_tokens_t megaco_localParam_names[] = {
3069     { "Unknown-token",              NULL }, /* 0 Pad so that the real headers start at index 1 */
3070     /* streamMode */
3071     { "Mode",                       "MO" }, /* 1 */
3072     { "ReservedValue",              "RV" }, /* 2 */
3073     { "ReservedGroup",              "RG" }, /* 3 */
3074     /* propertyParm         = pkgdName parmValue
3075      * Add more package names as needed.
3076      */
3077     { "h324/h223capr",              NULL }, /* 4 */
3078     { "h324/muxtbl_in",             NULL }, /* 5 */
3079     { "h324/muxtbl_out",            NULL }, /* 6 */
3080     { "ds/dscp",                    NULL }, /* 7 */
3081     { "gm/saf",                     NULL }, /* 8 */
3082     { "gm/sam",                     NULL }, /* 9 */
3083     { "gm/spf",                     NULL }, /* 10 */
3084     { "gm/spr",                     NULL }, /* 11 */
3085     { "gm/esas",                    NULL }, /* 12 */
3086     { "gm/lsa",                     NULL }, /* 13 */
3087     { "gm/esps",                    NULL }, /* 14 */
3088     { "gm/lsp",                     NULL }, /* 15 */
3089     { "gm/rsb",                     NULL }, /* 16 */
3090     { "tman/pol",                   NULL }, /* 17 */
3091     { "tman/sdr",                   NULL }, /* 18 */
3092     { "tman/mbs",                   NULL }, /* 19 */
3093     { "tman/pdr",                   NULL }, /* 20 */
3094     { "tman/dvt",                   NULL }, /* 21 */
3095     { "ipdc/realm",                 NULL }, /* 22 */
3096 };
3097
3098 /* Returns index of megaco_tokens_t */
3099 static gint find_megaco_localParam_names(tvbuff_t *tvb, int offset, guint header_len)
3100 {
3101     guint i;
3102
3103     for (i = 1; i < array_length(megaco_localParam_names); i++) {
3104         if (header_len == strlen(megaco_localParam_names[i].name) &&
3105             tvb_strncaseeql(tvb, offset, megaco_localParam_names[i].name, header_len) == 0)
3106             return i;
3107         if (megaco_localParam_names[i].compact_name != NULL &&
3108             header_len == strlen(megaco_localParam_names[i].compact_name) &&
3109             tvb_strncaseeql(tvb, offset, megaco_localParam_names[i].compact_name, header_len) == 0)
3110             return i;
3111     }
3112
3113     return -1;
3114 }
3115
3116 static void
3117 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)
3118 {
3119     gint tokenlen;
3120     guint token_name_len;
3121     gint tvb_offset = 0,tvb_help_offset;
3122     gint token_index = 0;
3123     gchar *msg;
3124     proto_item* item;
3125     guint8              code_str[3];
3126
3127     proto_tree  *megaco_LocalControl_tree;
3128     proto_item  *megaco_LocalControl_item;
3129
3130     tokenlen = tvb_next_offset - tvb_current_offset;
3131
3132     megaco_LocalControl_item = proto_tree_add_item(megaco_mediadescriptor_tree, hf_megaco_LocalControl_descriptor, tvb, tvb_current_offset, tokenlen, ENC_NA);
3133     megaco_LocalControl_tree = proto_item_add_subtree(megaco_LocalControl_item, ett_megaco_LocalControldescriptor);
3134
3135     while ( tvb_offset < tvb_next_offset && tvb_offset != -1 ){
3136
3137         tvb_help_offset = tvb_current_offset;
3138
3139         /*
3140          * Find local parameter name
3141          * localParm            = ( streamMode / propertyParm / reservedValueMode / reservedGroupMode )
3142          * pkgdName             = (PackageName SLASH ItemID) ;specific item
3143          *                    / (PackageName SLASH "*") ;all events in package
3144          *                    / ("*" SLASH "*") ; all events supported by the MG
3145          */
3146         /* Find token length */
3147         for (tvb_offset=tvb_current_offset; tvb_offset < tvb_next_offset; tvb_offset++){
3148             guint8 octet;
3149             octet = tvb_get_guint8(tvb, tvb_offset);
3150             if (!g_ascii_isalnum(octet)){
3151                 if ((octet!='/')&&(octet!='_')){
3152                     break;
3153                 }
3154             }
3155         }
3156         token_name_len = tvb_offset - tvb_current_offset;
3157         /* Debug Code
3158         proto_tree_add_format_text(megaco_LocalControl_tree, tvb, tvb_current_offset, token_name_len);
3159          */
3160         token_index = find_megaco_localParam_names(tvb, tvb_current_offset, token_name_len);
3161         /* Find start of parameter value */
3162         tvb_offset = tvb_find_guint8(tvb, tvb_offset , tvb_next_offset, '=');
3163         if (tvb_offset == -1) {
3164             expert_add_info(pinfo, megaco_LocalControl_item, &ei_megaco_parse_error);
3165             return;
3166         }
3167         /* Start search after '=' in case there is no SP*/
3168         tvb_offset++;
3169         tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset);
3170
3171         /* find if there are more parameters or not */
3172         tvb_offset = tvb_find_guint8(tvb, tvb_current_offset , tvb_offset, ',');
3173         if ( tvb_offset < 0 || tvb_offset > tvb_next_offset ){
3174             tvb_offset = tvb_next_offset;
3175         }
3176
3177         tokenlen = megaco_tvb_skip_wsp_return(tvb,tvb_offset-1) - tvb_current_offset;
3178         /* Debug Code
3179         proto_tree_add_format_text(megaco_LocalControl_tree, tvb, tvb_current_offset, tokenlen);
3180          */
3181         switch ( token_index ){
3182
3183         case MEGACO_MODETOKEN: /* Mode */
3184             proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_mode, tvb,
3185                 tvb_help_offset, tvb_offset-tvb_help_offset,
3186                 tvb_format_text(tvb, tvb_current_offset,
3187                 tokenlen));
3188             col_append_fstr(pinfo->cinfo, COL_INFO, " (Mode:%s)",tvb_format_text(tvb, tvb_current_offset,tokenlen));
3189             tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
3190             break;
3191
3192         case MEGACO_RESERVEDVALUETOKEN: /* ReservedValue */
3193             proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_reserve_value, tvb,
3194                     tvb_help_offset, tvb_offset-tvb_help_offset,
3195                     tvb_format_text(tvb, tvb_current_offset, tokenlen));
3196
3197             tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
3198             break;
3199         case MEGACO_RESERVEDGROUPTOKEN: /* ReservedGroup */
3200             proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_reserve_group, tvb,
3201                 tvb_help_offset, tvb_offset-tvb_help_offset,
3202                 tvb_format_text(tvb, tvb_current_offset, tokenlen));
3203             tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
3204             break;
3205
3206         case MEGACO_H324_H223CAPR: /* h324/h223capr */
3207             proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_h324_h223capr, tvb,
3208                 tvb_help_offset, tvb_offset-tvb_help_offset,
3209                 tvb_format_text(tvb, tvb_current_offset, tokenlen));
3210
3211             tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
3212             tokenlen = tvb_offset - tvb_help_offset;
3213             msg=tvb_format_text(tvb,tvb_help_offset, tokenlen);
3214             dissect_megaco_h324_h223caprn(tvb, pinfo, megaco_mediadescriptor_tree, tvb_help_offset, tokenlen, msg);
3215
3216             break;
3217
3218         case MEGACO_H324_MUXTBL_IN: /* h324/muxtbl_in */
3219
3220             proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_h324_muxtbl_in, tvb,
3221                 tvb_help_offset, tvb_offset-tvb_help_offset,
3222                 tvb_format_text(tvb, tvb_current_offset, tokenlen));
3223
3224             tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
3225
3226             tokenlen = tvb_offset - tvb_help_offset;
3227             /* Call the existing routine with tree = NULL to avoid an entry to the tree */
3228             dissect_megaco_h245(tvb, pinfo, NULL, tvb_help_offset, tokenlen, top_tree);
3229
3230             break;
3231
3232         case MEGACO_H324_MUXTBL_OUT:
3233
3234             proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_h324_muxtbl_out, tvb,
3235                 tvb_current_offset, tokenlen,
3236                 tvb_format_text(tvb, tvb_current_offset,
3237                 tokenlen));
3238
3239             tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
3240
3241             tokenlen = tvb_offset - tvb_help_offset;
3242             /* Call the existing routine with tree = NULL to avoid an entry to the tree */
3243             dissect_megaco_h245(tvb, pinfo, NULL, tvb_help_offset, tokenlen, top_tree);
3244
3245             break;
3246
3247         case MEGACO_DS_DSCP:
3248             tvb_get_nstringz0(tvb,tvb_current_offset,3,code_str);
3249             item = proto_tree_add_uint(megaco_LocalControl_tree, hf_megaco_ds_dscp, tvb,
3250                 tvb_help_offset, 1, (guint32) strtoul(code_str,NULL,16));
3251             proto_item_set_len(item, tvb_offset-tvb_help_offset);
3252             tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
3253             break;
3254
3255         case MEGACO_GM_SAF:
3256             proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_gm_saf, tvb,
3257                 tvb_help_offset, tvb_offset-tvb_help_offset, tvb_format_text(tvb, tvb_current_offset, tokenlen));
3258             tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
3259             break;
3260         case MEGACO_GM_SAM:
3261             proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_gm_sam, tvb,
3262                 tvb_help_offset, tvb_offset-tvb_help_offset, tvb_format_text(tvb, tvb_current_offset, tokenlen));
3263             tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
3264             break;
3265         case MEGACO_GM_SPF:
3266             proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_gm_spf, tvb,
3267                 tvb_help_offset, tvb_offset-tvb_help_offset, tvb_format_text(tvb, tvb_current_offset, tokenlen));
3268             tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
3269             break;
3270         case MEGACO_GM_SPR:
3271             proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_gm_spr, tvb,
3272                 tvb_help_offset, tvb_offset-tvb_help_offset, tvb_format_text(tvb, tvb_current_offset, tokenlen));
3273             tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
3274             break;
3275         case MEGACO_GM_ESAS:
3276             proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_gm_esas, tvb,
3277                 tvb_help_offset, tvb_offset-tvb_help_offset, tvb_format_text(tvb, tvb_current_offset, tokenlen));
3278             tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
3279             break;
3280         case MEGACO_GM_RSB:
3281             proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_gm_rsb, tvb,
3282                 tvb_help_offset, tvb_offset - tvb_help_offset, tvb_format_text(tvb, tvb_current_offset, tokenlen));
3283             tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset + 1);
3284             break;
3285             break;
3286         case MEGACO_TMAN_POL:
3287             proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_tman_pol, tvb,
3288                 tvb_help_offset, tvb_offset-tvb_help_offset, tvb_format_text(tvb, tvb_current_offset, tokenlen));
3289             tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
3290             break;
3291         case MEGACO_TMAN_SDR:
3292             proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_tman_sdr, tvb,
3293                 tvb_help_offset, tvb_offset-tvb_help_offset, tvb_format_text(tvb, tvb_current_offset, tokenlen));
3294             tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
3295             break;
3296         case MEGACO_TMAN_MBS:
3297             proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_tman_mbs, tvb,
3298                 tvb_help_offset, tvb_offset-tvb_help_offset, tvb_format_text(tvb, tvb_current_offset, tokenlen));
3299             tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
3300             break;
3301         case MEGACO_TMAN_PDR:
3302             proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_tman_pdr, tvb,
3303                 tvb_help_offset, tvb_offset-tvb_help_offset, tvb_format_text(tvb, tvb_current_offset, tokenlen));
3304             tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
3305             break;
3306         case MEGACO_TMAN_DVT:
3307             proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_tman_dvt, tvb,
3308                 tvb_help_offset, tvb_offset-tvb_help_offset, tvb_format_text(tvb, tvb_current_offset, tokenlen));
3309             tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
3310             break;
3311         case MEGACO_IPDC_REALM:
3312             proto_tree_add_string(megaco_LocalControl_tree, hf_megaco_ipdc_realm, tvb,
3313                 tvb_help_offset, tvb_offset-tvb_help_offset, tvb_format_text(tvb, tvb_current_offset, tokenlen));
3314             tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
3315             break;
3316
3317         default:
3318             tokenlen = tvb_offset - tvb_help_offset;
3319             proto_tree_add_format_text(megaco_LocalControl_tree, tvb, tvb_help_offset, tokenlen);
3320             tvb_current_offset = megaco_tvb_skip_wsp(tvb, tvb_offset +1);
3321
3322             break;
3323         }
3324     }
3325 }
3326
3327 static void
3328 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)
3329 {
3330     gint        tvb_len, token_index, tvb_offset, temp_offset;
3331     gint        tvb_current_offset,tvb_previous_offset,save_offset,tokenlen;
3332     gint        tvb_RBRKT, tvb_LBRKT;
3333     proto_tree* descriptor_tree;
3334     proto_item* descriptor_item;
3335
3336     tvb_len     = tvb_reported_length(tvb);
3337
3338     descriptor_tree = proto_tree_add_subtree(megaco_command_tree, tvb, tvb_descriptors_start_offset,
3339                                             tvb_descriptors_end_offset-tvb_descriptors_start_offset, ett_megaco_descriptors, &descriptor_item, "Descriptors");
3340
3341     tvb_LBRKT = megaco_tvb_skip_wsp(tvb, tvb_descriptors_start_offset +1);
3342
3343     tvb_previous_offset = tvb_LBRKT;
3344     tvb_RBRKT = tvb_descriptors_start_offset;
3345
3346
3347     do {
3348
3349         tvb_RBRKT = tvb_find_guint8(tvb, tvb_RBRKT+1,
3350             tvb_len, '}');
3351         tvb_LBRKT = tvb_find_guint8(tvb, tvb_LBRKT,
3352             tvb_len, '{');
3353
3354         tvb_current_offset  = tvb_find_guint8(tvb, tvb_previous_offset,
3355             tvb_len, ',');
3356
3357         if (tvb_current_offset == -1 || tvb_current_offset > tvb_descriptors_end_offset){
3358             tvb_current_offset = tvb_descriptors_end_offset;
3359
3360         }
3361         if (tvb_current_offset <= tvb_previous_offset) {
3362             expert_add_info_format(pinfo, descriptor_item, &ei_megaco_parse_error, "Parse error: Invalid offset");
3363             return;
3364         }
3365
3366         /* Descriptor includes no parameters */
3367
3368         if ( tvb_LBRKT > tvb_current_offset || tvb_LBRKT == -1 ){
3369
3370             if ( tvb_current_offset > tvb_RBRKT ){
3371                 tvb_current_offset = tvb_RBRKT;
3372             }
3373
3374             tvb_RBRKT = megaco_tvb_skip_wsp_return(tvb, tvb_current_offset-1)-1;
3375         }
3376
3377         /* Descriptor includes Parameters */
3378         if ( (tvb_current_offset > tvb_LBRKT && tvb_LBRKT != -1)){
3379
3380             while ( tvb_LBRKT != -1 && tvb_RBRKT > tvb_LBRKT ){
3381
3382
3383                 tvb_LBRKT  = tvb_find_guint8(tvb, tvb_LBRKT+1,
3384                     tvb_len, '{');
3385                 if ( tvb_LBRKT < tvb_RBRKT && tvb_LBRKT != -1)
3386                     tvb_RBRKT  = tvb_find_guint8(tvb, tvb_RBRKT+1,tvb_len, '}');
3387             }
3388
3389         }
3390
3391         /* Find token length */
3392         for (tvb_offset=tvb_previous_offset; tvb_offset < tvb_descriptors_end_offset -1; tvb_offset++){
3393             if (!g_ascii_isalpha(tvb_get_guint8(tvb, tvb_offset ))){
3394                 break;
3395             }
3396         }
3397         tokenlen =  tvb_offset - tvb_previous_offset;
3398         token_index = find_megaco_descriptors_names(tvb, tvb_previous_offset, tokenlen);
3399         if (tvb_RBRKT > tvb_descriptors_end_offset)
3400             tvb_RBRKT = tvb_descriptors_end_offset;
3401         switch ( token_index ){
3402         case MEGACO_MODEM_TOKEN:
3403             dissect_megaco_modemdescriptor(tvb, descriptor_tree, tvb_RBRKT, tvb_previous_offset);
3404             break;
3405         case MEGACO_MUX_TOKEN:
3406             dissect_megaco_multiplexdescriptor(tvb, descriptor_tree, tvb_RBRKT, tvb_previous_offset);
3407             break;
3408         case MEGACO_MEDIA_TOKEN:
3409             /*TODO: Move this to the top when all branches fixed !!!*/
3410             temp_offset = tvb_find_guint8(tvb, tvb_previous_offset,tvb_descriptors_end_offset, '{');
3411             save_offset = tvb_previous_offset;
3412
3413             tvb_previous_offset = megaco_tvb_skip_wsp(tvb, temp_offset +1);
3414             dissect_megaco_mediadescriptor(tvb, descriptor_tree, pinfo, tvb_RBRKT, tvb_previous_offset, save_offset, top_tree);
3415             break;
3416         case MEGACO_SIGNALS_TOKEN:
3417             dissect_megaco_signaldescriptor(tvb, pinfo, descriptor_tree, tvb_RBRKT, tvb_previous_offset, top_tree);
3418             break;
3419         case MEGACO_SERVICES_TOKEN:
3420             dissect_megaco_servicechangedescriptor(tvb, pinfo, descriptor_tree, tvb_RBRKT, tvb_previous_offset);
3421             break;
3422         case MEGACO_STATS_TOKEN:
3423             dissect_megaco_statisticsdescriptor(tvb, descriptor_tree, tvb_RBRKT, tvb_previous_offset);
3424             break;
3425         case MEGACO_ERROR_TOKEN:
3426             dissect_megaco_errordescriptor(tvb, pinfo, descriptor_tree, tvb_RBRKT, tvb_previous_offset);
3427             break;
3428         case MEGACO_EVENTS_TOKEN:
3429             dissect_megaco_eventsdescriptor(tvb, pinfo, descriptor_tree, tvb_RBRKT, tvb_previous_offset, top_tree);
3430             break;
3431         case MEGACO_AUDIT_TOKEN:
3432             dissect_megaco_auditdescriptor(tvb, descriptor_tree, pinfo, tvb_RBRKT, tvb_previous_offset);
3433             break;
3434         case MEGACO_DIGITMAP_TOKEN:
3435             dissect_megaco_digitmapdescriptor(tvb, descriptor_tree, tvb_RBRKT, tvb_previous_offset);
3436             break;
3437         case MEGACO_OE_TOKEN:
3438             /* ObservedEventsToken */
3439             dissect_megaco_observedeventsdescriptor(tvb, pinfo, descriptor_tree, tvb_RBRKT, tvb_previous_offset, top_tree);
3440             break;
3441         case MEGACO_TOPOLOGY_TOKEN:
3442             dissect_megaco_topologydescriptor(tvb, descriptor_tree, tvb_RBRKT, tvb_previous_offset);
3443             break;
3444         case MEGACO_PACKAGES_TOKEN:
3445             dissect_megaco_Packagesdescriptor(tvb, descriptor_tree, tvb_RBRKT, tvb_previous_offset);
3446             break;
3447         default:
3448             tokenlen =  (tvb_RBRKT+1) - tvb_previous_offset;
3449             proto_tree_add_expert(descriptor_tree, pinfo, &ei_megaco_no_descriptor, tvb, tvb_previous_offset, tokenlen);
3450             break;
3451         }
3452
3453         tvb_current_offset      = tvb_find_guint8(tvb, tvb_RBRKT, tvb_len, ',');
3454         if (tvb_current_offset == -1 || tvb_descriptors_end_offset < tvb_current_offset){
3455             tvb_current_offset = tvb_descriptors_end_offset;
3456         }
3457         tvb_previous_offset = megaco_tvb_skip_wsp(tvb, tvb_current_offset+1);
3458         tvb_LBRKT = tvb_previous_offset;
3459         tvb_RBRKT = tvb_previous_offset;
3460
3461     } while ( tvb_current_offset < tvb_descriptors_end_offset );
3462
3463 }
3464
3465 /* Copied from MGCP dissector, prints whole message in raw text */
3466
3467 static void tvb_raw_text_add(tvbuff_t *tvb, proto_tree *tree){
3468
3469     gint tvb_linebegin,tvb_lineend,linelen;
3470     proto_tree* text_tree;
3471
3472     tvb_linebegin = 0;
3473
3474     if (tree) {
3475         text_tree = proto_tree_add_subtree(tree, tvb, 0, -1, ett_megaco_raw_text, NULL, "-------------- (RAW text output) ---------------");
3476
3477         do {
3478             linelen = tvb_find_line_end(tvb,tvb_linebegin,-1,&tvb_lineend,FALSE);
3479             proto_tree_add_format_wsp_text(text_tree, tvb, tvb_linebegin, linelen);
3480             tvb_linebegin = tvb_lineend;
3481         } while (tvb_offset_exists(tvb, tvb_lineend) && linelen > 0);
3482     }
3483 }
3484
3485 /*
3486 * megaco_tvb_skip_wsp - Returns the position in tvb of the first non-whitespace
3487 *        character following offset or offset + maxlength -1 whichever
3488 *        is smaller.
3489 *
3490 * Parameters:
3491 * tvb - The tvbuff in which we are skipping whitespaces, tab and end_of_line characters.
3492 * offset - The offset in tvb from which we begin trying to skip whitespace.
3493 *
3494 * Returns: The position in tvb of the first non-whitespace
3495 */
3496 static gint megaco_tvb_skip_wsp(tvbuff_t* tvb, gint offset ){
3497     gint counter = offset;
3498     gint end = tvb_reported_length(tvb);
3499
3500     for(counter = offset; counter < end &&
3501         (g_ascii_isspace(tvb_get_guint8(tvb,counter))); counter++);
3502     return (counter);
3503 }
3504
3505 static gint megaco_tvb_skip_wsp_return(tvbuff_t* tvb, gint offset){
3506     gint counter = offset;
3507     gint end = 0;
3508
3509     for(counter = offset; counter > end &&
3510         (g_ascii_isspace(tvb_get_guint8(tvb,counter))); counter--);
3511     counter++;
3512     return (counter);
3513 }
3514
3515 static gint megaco_tvb_find_token(tvbuff_t* tvb, gint offset, gint maxlength){
3516     gint counter = 0;
3517     gint pos = offset;
3518     guchar needle;
3519
3520     do {
3521         pos = tvb_ws_mempbrk_pattern_guint8(tvb, pos + 1, maxlength, &pbrk_braces, &needle);
3522         if(pos == -1)
3523             return -1;
3524         switch(needle){
3525         case '{':
3526             counter++;
3527             break;
3528         case '}':
3529             counter--;
3530             break;
3531         default:
3532             break;
3533         }
3534     } while (counter>0);
3535     if(counter<0)
3536         return -1;
3537     else
3538     {
3539         pos = megaco_tvb_skip_wsp(tvb,pos+1);
3540         return pos;
3541     }
3542 }
3543
3544 static void
3545 megaco_fmt_content( gchar *result, guint32 context )
3546 {
3547     switch(context)
3548     {
3549     case CHOOSE_CONTEXT:
3550     case ALL_CONTEXTS:
3551     case NULL_CONTEXT:
3552         g_strlcpy(result, val_to_str_const(context, megaco_context_vals, "Unknown"), ITEM_LABEL_LENGTH);
3553         break;
3554     default:
3555         g_snprintf( result, ITEM_LABEL_LENGTH, "%d", context);
3556     }
3557 }
3558
3559 void
3560 proto_register_megaco(void)
3561 {
3562     static hf_register_info hf[] = {
3563         { &hf_megaco_audititem,
3564           { "Audit Item", "megaco.audititem", FT_STRING, BASE_NONE, NULL, 0x0,
3565             "Identity of item to be audited", HFILL }},
3566         { &hf_megaco_audit_descriptor,
3567           { "Audit Descriptor", "megaco.audit", FT_NONE, BASE_NONE, NULL, 0x0,
3568             "Audit Descriptor of the megaco Command", HFILL }},
3569 #if 0
3570         { &hf_megaco_command_line,
3571           { "Command line", "megaco.command_line", FT_STRING, BASE_NONE, NULL, 0x0,
3572             "Commands of this message", HFILL }},
3573 #endif
3574         { &hf_megaco_command,
3575           { "Command", "megaco.command", FT_STRING, BASE_NONE, NULL, 0x0,
3576             NULL, HFILL }},
3577         { &hf_megaco_command_optional,
3578           { "Optional Command", "megaco.command_optional", FT_NONE, BASE_NONE, NULL, 0x0,
3579             NULL, HFILL }},
3580         { &hf_megaco_wildcard_response,
3581           { "Wildcarded response to a command", "megaco.wildcard_response", FT_NONE, BASE_NONE, NULL, 0x0,
3582             NULL, HFILL }},
3583
3584         { &hf_megaco_Context,
3585           { "Context", "megaco.context", FT_UINT32, BASE_CUSTOM, CF_FUNC(megaco_fmt_content), 0x0,
3586             "Context ID of this message", HFILL }},
3587         { &hf_megaco_digitmap_descriptor,
3588           { "DigitMap Descriptor", "megaco.digitmap", FT_STRING, BASE_NONE, NULL, 0x0,
3589             "DigitMap Descriptor of the megaco Command", HFILL }},
3590         { &hf_megaco_error_descriptor,
3591           { "ERROR Descriptor", "megaco.error", FT_NONE, BASE_NONE, NULL, 0x0,
3592             "Error Descriptor of the megaco Command", HFILL }},
3593         { &hf_megaco_error_code,
3594           { "ERROR Code", "megaco.error_code", FT_UINT32, BASE_DEC, VALS(MEGACO_error_code_vals), 0x0,
3595             "Error Code of the megaco Command", HFILL }},
3596         { &hf_megaco_error_string,
3597           { "ERROR String", "megaco.error_string", FT_STRING, BASE_NONE, NULL, 0x0,
3598             "Error String of the megaco Command", HFILL }},
3599         { &hf_megaco_Event_Buffer_Control,
3600           { "Event Buffer Control", "megaco.eventbuffercontrol", FT_STRING, BASE_NONE, NULL, 0x0,
3601             "Event Buffer Control in Termination State Descriptor", HFILL }},
3602         { &hf_megaco_events_descriptor,
3603           { "Events Descriptor", "megaco.events", FT_NONE, BASE_NONE, NULL, 0x0,
3604             "Events Descriptor of the megaco Command", HFILL }},
3605         { &hf_megaco_Local_descriptor,
3606           { "Local Descriptor", "megaco.localdescriptor", FT_NONE, BASE_NONE, NULL, 0x0,
3607             "Local Descriptor in Media Descriptor", HFILL }},
3608         { &hf_megaco_LocalControl_descriptor,
3609           { "Local Control Descriptor", "megaco.localcontroldescriptor", FT_NONE, BASE_NONE, NULL, 0x0,
3610             "Local Control Descriptor in Media Descriptor", HFILL }},
3611         { &hf_megaco_media_descriptor,
3612           { "Media Descriptor", "megaco.media", FT_NONE, BASE_NONE, NULL, 0x0,
3613             "Media Descriptor of the megaco Command", HFILL }},
3614         { &hf_megaco_modem_descriptor,
3615           { "Modem Descriptor", "megaco.modem", FT_STRING, BASE_NONE, NULL, 0x0,
3616             "Modem Descriptor of the megaco Command", HFILL }},
3617         { &hf_megaco_mode,
3618           { "Mode", "megaco.mode", FT_STRING, BASE_NONE, NULL, 0x0,
3619             "Mode  sendonly/receiveonly/inactive/loopback", HFILL }},
3620         { &hf_megaco_multiplex_descriptor,
3621           { "Multiplex Descriptor", "megaco.multiplex", FT_STRING, BASE_NONE, NULL, 0x0,
3622             "Multiplex Descriptor of the megaco Command", HFILL }},
3623         { &hf_megaco_observedevents_descriptor,
3624           { "Observed Events Descriptor", "megaco.observedevents", FT_NONE, BASE_NONE, NULL, 0x0,
3625             "Observed Events Descriptor of the megaco Command", HFILL }},
3626         { &hf_megaco_packages_descriptor,
3627           { "Packages Descriptor", "megaco.packagesdescriptor", FT_STRING, BASE_NONE, NULL, 0x0,
3628             NULL, HFILL }},
3629         { &hf_megaco_pkgdname,
3630           { "pkgdName", "megaco.pkgdname", FT_STRING, BASE_NONE, NULL, 0x0,
3631             "PackageName SLASH ItemID", HFILL }},
3632 #if 0
3633         { &hf_megaco_Remote_descriptor,
3634           { "Remote Descriptor", "megaco.remotedescriptor", FT_STRING, BASE_NONE, NULL, 0x0,
3635             "Remote Descriptor in Media Descriptor", HFILL }},
3636 #endif
3637         { &hf_megaco_reserve_group,
3638           { "Reserve Group", "megaco.reservegroup", FT_STRING, BASE_NONE, NULL, 0x0,
3639             "Reserve Group on or off", HFILL }},
3640         { &hf_megaco_h324_muxtbl_in,
3641           { "h324/muxtbl_in", "megaco.h324_muxtbl_in", FT_STRING, BASE_NONE, NULL, 0x0,
3642             NULL, HFILL }},
3643         { &hf_megaco_h324_muxtbl_out,
3644           { "h324/muxtbl_out", "megaco.h324_muxtbl_out", FT_STRING, BASE_NONE, NULL, 0x0,
3645             NULL, HFILL }},
3646         { &hf_megaco_ds_dscp,
3647           { "Differentiated Services Code Point", "megaco.ds_dscp", FT_UINT32, BASE_HEX|BASE_EXT_STRING, &dscp_vals_ext, 0x0,
3648             NULL, HFILL }},
3649         { &hf_megaco_gm_saf,
3650           { "Remote Source Address Filtering", "megaco.gm_saf", FT_STRING, BASE_NONE, NULL, 0x0,
3651             NULL, HFILL }},
3652         { &hf_megaco_gm_sam,
3653           { "Remote Source Address Mask", "megaco.gm_sam", FT_STRING, BASE_NONE, NULL, 0x0,
3654             NULL, HFILL }},
3655         { &hf_megaco_gm_spf,
3656           { "Remote Source Port Filtering", "megaco.gm_spf", FT_STRING, BASE_NONE, NULL, 0x0,
3657             NULL, HFILL }},
3658         { &hf_megaco_gm_spr,
3659           { "Remote Source Port Range", "megaco.gm_spr", FT_STRING, BASE_NONE, NULL, 0x0,
3660             NULL, HFILL }},
3661         { &hf_megaco_gm_esas,
3662           { "Explicit Source Address Setting", "megaco.gm_esas", FT_STRING, BASE_NONE, NULL, 0x0,
3663             NULL, HFILL }},
3664         { &hf_megaco_tman_pol,
3665           { "Policing", "megaco.tman_pol", FT_STRING, BASE_NONE, NULL, 0x0,
3666             NULL, HFILL }},
3667         { &hf_megaco_gm_rsb,
3668           { "RTCP Allocation Specific Behaviour", "megaco.gm_rsb", FT_STRING, BASE_NONE, NULL, 0x0,
3669             NULL, HFILL }},
3670         { &hf_megaco_tman_sdr,
3671           { "Sustainable Data Rate", "megaco.tman_sdr", FT_STRING, BASE_NONE, NULL, 0x0,
3672             NULL, HFILL }},
3673         { &hf_megaco_tman_mbs,
3674           { "Maximum Burst Rate", "megaco.tman_mbs", FT_STRING, BASE_NONE, NULL, 0x0,
3675             NULL, HFILL }},
3676         { &hf_megaco_tman_pdr,
3677           { "Peak Data Rate", "megaco.tman_pdr", FT_STRING, BASE_NONE, NULL, 0x0,
3678             NULL, HFILL }},
3679         { &hf_megaco_tman_dvt,
3680           { "Delay Variation Tolerance", "megaco.tman_dvt", FT_STRING, BASE_NONE, NULL, 0x0,
3681             NULL, HFILL }},
3682         { &hf_megaco_ipdc_realm,
3683           { "IP Realm Identifier", "megaco.ipdc_realm", FT_STRING, BASE_NONE, NULL, 0x0,
3684             NULL, HFILL }},
3685         { &hf_megaco_h324_h223capr,
3686           { "h324/h223capr", "megaco.h324_h223capr", FT_STRING, BASE_NONE, NULL, 0x0,
3687             NULL, HFILL }},
3688         { &hf_megaco_reserve_value,
3689           { "Reserve Value", "megaco.reservevalue", FT_STRING, BASE_NONE, NULL, 0x0,
3690             "Reserve Value on or off", HFILL }},
3691         { &hf_megaco_requestid,
3692           { "RequestID", "megaco.requestid", FT_UINT32, BASE_DEC, NULL, 0x0,
3693             "RequestID in Events or Observedevents Descriptor", HFILL }},
3694 #if 0
3695         { &hf_megaco_servicechange_descriptor,
3696           { "Service Change Descriptor", "megaco.servicechange", FT_STRING, BASE_NONE, NULL, 0x0,
3697             "Service Change Descriptor of the megaco Command", HFILL }},
3698 #endif
3699         { &hf_megaco_Service_State,
3700           { "Service State", "megaco.servicestates", FT_STRING, BASE_NONE, NULL, 0x0,
3701             "Service States in Termination State Descriptor", HFILL }},
3702         { &hf_megaco_signal_descriptor,
3703           { "Signal Descriptor", "megaco.signal", FT_NONE, BASE_NONE, NULL, 0x0,
3704             "Signal Descriptor of the megaco Command", HFILL }},
3705         { &hf_megaco_statistics_descriptor,
3706           { "Statistics Descriptor", "megaco.statistics", FT_NONE, BASE_NONE, NULL, 0x0,
3707             "Statistics Descriptor of the megaco Command", HFILL }},
3708         { &hf_megaco_streamid,
3709           { "StreamID", "megaco.streamid", FT_UINT32, BASE_DEC, NULL, 0x0,
3710             "StreamID in the Media Descriptor", HFILL }},
3711         { &hf_megaco_termid,
3712           { "Termination ID", "megaco.termid", FT_STRING, BASE_NONE, NULL, 0x0,
3713             "Termination ID of this Command", HFILL }},
3714         { &hf_megaco_TerminationState_descriptor,
3715           { "Termination State Descriptor", "megaco.terminationstate", FT_NONE, BASE_NONE, NULL, 0x0,
3716             "Termination State Descriptor in Media Descriptor", HFILL }},
3717         { &hf_megaco_topology_descriptor,
3718           { "Topology Descriptor", "megaco.topology", FT_STRING, BASE_NONE, NULL, 0x0,
3719             "Topology Descriptor of the megaco Command", HFILL }},
3720         { &hf_megaco_transaction,
3721           { "Transaction", "megaco.transaction", FT_STRING, BASE_NONE, NULL, 0x0,
3722             "Message Originator", HFILL }},
3723         { &hf_megaco_transid,
3724           { "Transaction ID", "megaco.transid", FT_UINT32, BASE_DEC, NULL, 0x0,
3725             "Transaction ID of this message", HFILL }},
3726         { &hf_megaco_mId,
3727           { "MediagatewayID", "megaco.mId", FT_STRING, BASE_NONE, NULL, 0x0,
3728             "Mediagateway ID", HFILL }},
3729         { &hf_megaco_version,
3730           { "Version", "megaco.version", FT_STRING, BASE_NONE, NULL, 0x0,
3731             NULL, HFILL }},
3732         { &hf_megaco_start,
3733           { "Start token", "megaco.start_token", FT_STRING, BASE_NONE, NULL, 0x0,
3734             NULL, HFILL }},
3735         { &hf_megaco_h245,
3736           { "h245", "megaco.h245", FT_NONE, BASE_NONE, NULL, 0x0,
3737             "Embedded H.245 message", HFILL }},
3738         { &hf_megaco_h223Capability,
3739           { "h223Capability", "megaco.h245.h223Capability", FT_NONE, BASE_NONE, NULL, 0,
3740             "megaco.h245.H223Capability", HFILL }},
3741
3742         GCP_HF_ARR_ELEMS("megaco",megaco_ctx_ids),
3743
3744         /* Add more fields here */
3745     };
3746     static gint *ett[] = {
3747         &ett_megaco,
3748         &ett_megaco_message,
3749         &ett_megaco_message_body,
3750         &ett_megaco_context,
3751         &ett_megaco_command_line,
3752         &ett_megaco_descriptors,
3753         &ett_megaco_raw_text,
3754         &ett_megaco_error_descriptor,
3755         &ett_megaco_mediadescriptor,
3756         &ett_megaco_TerminationState,
3757         &ett_megaco_Remotedescriptor,
3758         &ett_megaco_Localdescriptor,
3759         &ett_megaco_LocalControldescriptor,
3760         &ett_megaco_auditdescriptor,
3761         &ett_megaco_eventsdescriptor,
3762         &ett_megaco_statisticsdescriptor,
3763         &ett_megaco_observedeventsdescriptor,
3764         &ett_megaco_observedevent,
3765         &ett_megaco_packagesdescriptor,
3766         &ett_megaco_requestedevent,
3767         &ett_megaco_signalsdescriptor,
3768         &ett_megaco_requestedsignal,
3769         &ett_megaco_h245,
3770         GCP_ETT_ARR_ELEMS(megaco_ctx_ids),
3771     };
3772
3773     static ei_register_info ei[] = {
3774         { &ei_megaco_errored_command, { "megaco.errored_command", PI_RESPONSE_CODE, PI_WARN, "Errored Command", EXPFILL }},
3775         { &ei_megaco_parse_error, { "megaco.parse_error", PI_MALFORMED, PI_ERROR, "Parse error", EXPFILL }},
3776         { &ei_megaco_error_descriptor_transaction_list, { "megaco.error_descriptor_transaction_list.invalid", PI_MALFORMED, PI_ERROR, "Sorry, can't understand errorDescriptor / transactionList", EXPFILL }},
3777         { &ei_megaco_audit_descriptor, { "megaco.audit.malformed", PI_MALFORMED, PI_ERROR, "Badly constructed audit descriptor (no { )", EXPFILL }},
3778         { &ei_megaco_signal_descriptor, { "megaco.signal_descriptor.empty", PI_PROTOCOL, PI_NOTE, "Empty Signal Descriptor", EXPFILL }},
3779         { &ei_megaco_no_command, { "megaco.no_command", PI_PROTOCOL, PI_WARN, "No Command detectable", EXPFILL }},
3780         { &ei_megaco_no_descriptor, { "megaco.no_descriptor", PI_PROTOCOL, PI_WARN, "No Descriptor detectable", EXPFILL }},
3781         { &ei_megaco_reason_invalid, { "megaco.change_reason.invalid", PI_MALFORMED, PI_ERROR, "Invalid Service Change Reason", EXPFILL }},
3782         { &ei_megaco_error_code_invalid, { "megaco.error_code.invalid", PI_MALFORMED, PI_ERROR, "Invalid error code", EXPFILL }}
3783     };
3784
3785     module_t *megaco_module;
3786     expert_module_t* expert_megaco;
3787
3788     proto_megaco = proto_register_protocol("MEGACO", "MEGACO", "megaco");
3789
3790     megaco_text_handle = register_dissector("megaco", dissect_megaco_text, proto_megaco);
3791
3792     proto_register_field_array(proto_megaco, hf, array_length(hf));
3793     proto_register_subtree_array(ett, array_length(ett));
3794     expert_megaco = expert_register_protocol(proto_megaco);
3795     expert_register_field_array(expert_megaco, ei, array_length(ei));
3796
3797     /* Register our configuration options, particularly our ports */
3798
3799     megaco_module = prefs_register_protocol(proto_megaco, proto_reg_handoff_megaco);
3800
3801     prefs_register_uint_preference(megaco_module, "sctp.txt_port",
3802                                    "MEGACO Text SCTP Port",
3803                                    "Set the SCTP port for MEGACO text messages",
3804                                    10, &global_megaco_txt_sctp_port);
3805
3806 #if 0
3807     prefs_register_uint_preference(megaco_module, "sctp.bin_port",
3808                                    "MEGACO Binary SCTP Port",
3809                                    "Set the SCTP port for MEGACO binary messages",
3810                                    10, &global_megaco_bin_sctp_port);
3811
3812     prefs_register_uint_preference(megaco_module, "tcp.bin_port",
3813                                    "MEGACO Binary TCP Port",
3814                                    "Set the TCP port for MEGACO binary messages",
3815                                    10, &global_megaco_bin_tcp_port);
3816
3817     prefs_register_uint_preference(megaco_module, "udp.bin_port",
3818                                    "MEGACO Binary UDP Port",
3819                                    "Set the UDP port for MEGACO binary messages",
3820                                    10, &global_megaco_bin_udp_port);
3821 #endif
3822
3823     prefs_register_bool_preference(megaco_module, "display_raw_text",
3824                                    "Display raw text for MEGACO message",
3825                                    "Specifies that the raw text of the "
3826                                    "MEGACO message should be displayed "
3827                                    "instead of (or in addition to) the "
3828                                    "dissection tree",
3829                                    &global_megaco_raw_text);
3830
3831     prefs_register_bool_preference(megaco_module, "display_dissect_tree",
3832                                    "Display tree dissection for MEGACO message",
3833                                    "Specifies that the dissection tree of the "
3834                                    "MEGACO message should be displayed "
3835                                    "instead of (or in addition to) the "
3836                                    "raw text",
3837                                    &global_megaco_dissect_tree);
3838     prefs_register_bool_preference(megaco_module, "ctx_info",
3839                                    "Track Context",
3840                                    "Maintain relationships between transactions and contexts "
3841                                    "and display an extra tree showing context data",
3842                                    &keep_persistent_data);
3843
3844     megaco_tap = register_tap("megaco");
3845
3846     /* compile patterns */
3847     ws_mempbrk_compile(&pbrk_whitespace, " \t\r\n");
3848     ws_mempbrk_compile(&pbrk_braces, "{}");
3849
3850     register_rtd_table(proto_megaco, NULL, 1, NUM_TIMESTATS, megaco_message_type, megacostat_packet, megacostat_filtercheck);
3851 }
3852
3853 /* Register all the bits needed with the filtering engine */
3854 /* The registration hand-off routine */
3855 void
3856 proto_reg_handoff_megaco(void)
3857 {
3858     static gboolean megaco_prefs_initialized = FALSE;
3859     static dissector_handle_t megaco_text_tcp_handle;
3860     /*
3861     * Variables to allow for proper deletion of dissector registration when
3862     * the user changes port from the gui.
3863     */
3864     static guint txt_sctp_port;
3865 #if 0
3866     static guint bin_sctp_port;
3867     static guint bin_tcp_port;
3868     static guint bin_udp_port;
3869 #endif
3870
3871     if (!megaco_prefs_initialized) {
3872         sdp_handle = find_dissector_add_dependency("sdp", proto_megaco);
3873         h245_handle = find_dissector_add_dependency("h245dg", proto_megaco);
3874         h248_handle = find_dissector_add_dependency("h248", proto_megaco);
3875         h248_otp_handle = find_dissector_add_dependency("h248_otp", proto_megaco);
3876         data_handle = find_dissector("data");
3877
3878         megaco_text_tcp_handle = create_dissector_handle(dissect_megaco_text_tcp, proto_megaco);
3879
3880         dissector_add_uint_with_preference("tcp.port", PORT_MEGACO_TXT, megaco_text_tcp_handle);
3881         dissector_add_uint_with_preference("udp.port", PORT_MEGACO_TXT, megaco_text_handle);
3882         dissector_add_uint("sctp.ppi", H248_PAYLOAD_PROTOCOL_ID,   megaco_text_handle);
3883
3884         megaco_prefs_initialized = TRUE;
3885     } else {
3886         dissector_delete_uint("sctp.port", txt_sctp_port, megaco_text_handle);
3887     }
3888
3889     /* Set our port number for future use */
3890
3891     txt_sctp_port = global_megaco_txt_sctp_port;
3892
3893     dissector_add_uint("sctp.port", global_megaco_txt_sctp_port, megaco_text_handle);
3894
3895     exported_pdu_tap = find_tap_id(EXPORT_PDU_TAP_NAME_LAYER_7);
3896
3897 }
3898
3899 /*
3900  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
3901  *
3902  * Local variables:
3903  * c-basic-offset: 4
3904  * tab-width: 8
3905  * indent-tabs-mode: nil
3906  * End:
3907  *
3908  * vi: set shiftwidth=4 tabstop=8 expandtab:
3909  * :indentSize=4:tabSize=8:noTabs=true:
3910  */