23b1d2d1b8abce3af2609ab73463d00191465fc9
[obnox/wireshark/wip.git] / epan / dissectors / packet-mgcp.c
1 /* packet-mgcp.c
2  * Routines for mgcp packet disassembly
3  * RFC 2705
4  * RFC 3435 (obsoletes 2705): Media Gateway Control Protocol (MGCP) Version 1.0
5  * RFC 3660: Basic MGCP Packages
6  * RFC 3661: MGCP Return Code Usage
7  * NCS 1.0: PacketCable Network-Based Call Signaling Protocol Specification,
8  *          PKT-SP-EC-MGCP-I09-040113, January 13, 2004, Cable Television
9  *          Laboratories, Inc., http://www.PacketCable.com/
10  * www.iana.org/assignments/mgcp-localconnectionoptions
11  *
12  * $Id$
13  *
14  * Copyright (c) 2000 by Ed Warnicke <hagbard@physics.rutgers.edu>
15  * Copyright (c) 2004 by Thomas Anders <thomas.anders [AT] blue-cable.de>
16  *
17  * Wireshark - Network traffic analyzer
18  * By Gerald Combs <gerald@wireshark.org>
19  * Copyright 1999 Gerald Combs
20  *
21  * This program is free software; you can redistribute it and/or
22  * modify it under the terms of the GNU General Public License
23  * as published by the Free Software Foundation; either version 2
24  * of the License, or (at your option) any later version.
25  *
26  * This program is distributed in the hope that it will be useful,
27  * but WITHOUT ANY WARRANTY; without even the implied warranty of
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
29  * GNU General Public License for more details.
30  *
31  * You should have received a copy of the GNU General Public License
32  * along with this program; if not, write to the Free Software
33  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
34  */
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include <stdlib.h>
41 #include <ctype.h>
42 #include <string.h>
43
44 #include <epan/packet.h>
45 #include <epan/emem.h>
46 #include <epan/prefs.h>
47 #include <epan/conversation.h>
48 #include <epan/tap.h>
49 #include <epan/strutil.h>
50 #include "packet-mgcp.h"
51
52
53 #define TCP_PORT_MGCP_GATEWAY 2427
54 #define UDP_PORT_MGCP_GATEWAY 2427
55 #define TCP_PORT_MGCP_CALLAGENT 2727
56 #define UDP_PORT_MGCP_CALLAGENT 2727
57
58
59 /* Define the mgcp proto */
60 static int proto_mgcp = -1;
61
62 /* Define many many headers for mgcp */
63 static int hf_mgcp_req = -1;
64 static int hf_mgcp_req_verb = -1;
65 static int hf_mgcp_req_endpoint = -1;
66 static int hf_mgcp_req_frame = -1;
67 static int hf_mgcp_rsp = -1;
68 static int hf_mgcp_rsp_frame = -1;
69 static int hf_mgcp_time = -1;
70 static int hf_mgcp_transid = -1;
71 static int hf_mgcp_version = -1;
72 static int hf_mgcp_rsp_rspcode = -1;
73 static int hf_mgcp_rsp_rspstring = -1;
74 static int hf_mgcp_params = -1;
75 static int hf_mgcp_param_rspack = -1;
76 static int hf_mgcp_param_bearerinfo = -1;
77 static int hf_mgcp_param_callid = -1;
78 static int hf_mgcp_param_connectionid = -1;
79 static int hf_mgcp_param_secondconnectionid = -1;
80 static int hf_mgcp_param_notifiedentity = -1;
81 static int hf_mgcp_param_requestid = -1;
82 static int hf_mgcp_param_localconnoptions = -1;
83 static int hf_mgcp_param_localconnoptions_p = -1;
84 static int hf_mgcp_param_localconnoptions_a = -1;
85 static int hf_mgcp_param_localconnoptions_s = -1;
86 static int hf_mgcp_param_localconnoptions_e = -1;
87 static int hf_mgcp_param_localconnoptions_scrtp = -1;
88 static int hf_mgcp_param_localconnoptions_scrtcp = -1;
89 static int hf_mgcp_param_localconnoptions_b = -1;
90 static int hf_mgcp_param_localconnoptions_esccd = -1;
91 static int hf_mgcp_param_localconnoptions_escci = -1;
92 static int hf_mgcp_param_localconnoptions_dqgi = -1;
93 static int hf_mgcp_param_localconnoptions_dqrd = -1;
94 static int hf_mgcp_param_localconnoptions_dqri = -1;
95 static int hf_mgcp_param_localconnoptions_dqrr = -1;
96 static int hf_mgcp_param_localconnoptions_k = -1;
97 static int hf_mgcp_param_localconnoptions_gc = -1;
98 static int hf_mgcp_param_localconnoptions_fmtp = -1;
99 static int hf_mgcp_param_localconnoptions_nt = -1;
100 static int hf_mgcp_param_localconnoptions_ofmtp = -1;
101 static int hf_mgcp_param_localconnoptions_r = -1;
102 static int hf_mgcp_param_localconnoptions_t = -1;
103 static int hf_mgcp_param_localconnoptions_rcnf = -1;
104 static int hf_mgcp_param_localconnoptions_rdir = -1;
105 static int hf_mgcp_param_localconnoptions_rsh = -1;
106 static int hf_mgcp_param_connectionmode = -1;
107 static int hf_mgcp_param_reqevents = -1;
108 static int hf_mgcp_param_restartmethod = -1;
109 static int hf_mgcp_param_restartdelay = -1;
110 static int hf_mgcp_param_signalreq  = -1;
111 static int hf_mgcp_param_digitmap = -1;
112 static int hf_mgcp_param_observedevent = -1;
113 static int hf_mgcp_param_connectionparam = -1;
114 static int hf_mgcp_param_connectionparam_ps = -1;
115 static int hf_mgcp_param_connectionparam_os = -1;
116 static int hf_mgcp_param_connectionparam_pr = -1;
117 static int hf_mgcp_param_connectionparam_or = -1;
118 static int hf_mgcp_param_connectionparam_pl = -1;
119 static int hf_mgcp_param_connectionparam_ji = -1;
120 static int hf_mgcp_param_connectionparam_la = -1;
121 static int hf_mgcp_param_connectionparam_pcrps = -1;
122 static int hf_mgcp_param_connectionparam_pcros = -1;
123 static int hf_mgcp_param_connectionparam_pcrpl = -1;
124 static int hf_mgcp_param_connectionparam_pcrji = -1;
125 static int hf_mgcp_param_connectionparam_x = -1;
126 static int hf_mgcp_param_reasoncode = -1;
127 static int hf_mgcp_param_eventstates = -1;
128 static int hf_mgcp_param_specificendpoint = -1;
129 static int hf_mgcp_param_secondendpointid = -1;
130 static int hf_mgcp_param_reqinfo = -1;
131 static int hf_mgcp_param_quarantinehandling = -1;
132 static int hf_mgcp_param_detectedevents = -1;
133 static int hf_mgcp_param_capabilities = -1;
134 static int hf_mgcp_param_maxmgcpdatagram = -1;
135 static int hf_mgcp_param_packagelist = -1;
136 static int hf_mgcp_param_extension = -1;
137 static int hf_mgcp_param_extension_critical = -1;
138 static int hf_mgcp_param_invalid = -1;
139 static int hf_mgcp_messagecount = -1;
140 static int hf_mgcp_dup = -1;
141 static int hf_mgcp_req_dup = -1;
142 static int hf_mgcp_req_dup_frame = -1;
143 static int hf_mgcp_rsp_dup = -1;
144 static int hf_mgcp_rsp_dup_frame = -1;
145
146 static const value_string mgcp_return_code_vals[] = {
147         {000, "Response Acknowledgement"},
148         {100, "The transaction is currently being executed.  An actual completion message will follow on later."},
149         {101, "The transaction has been queued for execution.  An actual completion message will follow later."},
150         {200, "The requested transaction was executed normally."},
151         {250, "The connection was deleted."},
152         {400, "The transaction could not be executed, due to a transient error."},
153         {401, "The phone is already off hook"},
154         {402, "The phone is already on hook"},
155         {403, "The transaction could not be executed, because the endpoint does not have sufficient resources at this time"},
156         {404, "Insufficient bandwidth at this time"},
157         {405, "The transaction could not be executed, because the endpoint is \"restarting\"."},
158         {406, "Transaction time-out.  The transaction did not complete in a reasonable period of time and has been aborted."},
159         {407, "Transaction aborted.  The transaction was aborted by some external action, e.g., a ModifyConnection command aborted by a DeleteConnection command."},
160         {409, "The transaction could not be executed because of internal overload."},
161         {410, "No endpoint available.  A valid \"any of\" wildcard was used, however there was no endpoint available to satisfy the request."},
162         {500, "The transaction could not be executed, because the endpoint is unknown."},
163         {501, "The transaction could not be executed, because the endpoint is not ready."},
164         {502, "The transaction could not be executed, because the endpoint does not have sufficient resources"},
165         {503, "\"All of\" wildcard too complicated."},
166         {504, "Unknown or unsupported command."},
167         {505, "Unsupported RemoteConnectionDescriptor."},
168         {506, "Unable to satisfy both LocalConnectionOptions and RemoteConnectionDescriptor."},
169         {507, "Unsupported functionality."},
170         {508, "Unknown or unsupported quarantine handling."},
171         {509, "Error in RemoteConnectionDescriptor."},
172         {510, "The transaction could not be executed, because a protocol error was detected."},
173         {511, "The transaction could not be executed, because the command contained an unrecognized extension."},
174         {512, "The transaction could not be executed, because the gateway is not equipped to detect one of the requested events."},
175         {513, "The transaction could not be executed, because the gateway is not equipped to generate one of the requested signals."},
176         {514, "The transaction could not be executed, because the gateway cannot send the specified announcement."},
177         {515, "The transaction refers to an incorrect connection-id (may have been already deleted)"},
178         {516, "The transaction refers to an unknown call-id."},
179         {517, "Unsupported or invalid mode."},
180         {518, "Unsupported or unknown package."},
181         {519, "Endpoint does not have a digit map."},
182         {520, "The transaction could not be executed, because the endpoint is 'restarting'."},
183         {521, "Endpoint redirected to another Call Agent."},
184         {522, "No such event or signal."},
185         {523, "Unknown action or illegal combination of actions"},
186         {524, "Internal inconsistency in LocalConnectionOptions"},
187         {525, "Unknown extension in LocalConnectionOptions"},
188         {526, "Insufficient bandwidth"},
189         {527, "Missing RemoteConnectionDescriptor"},
190         {528, "Incompatible protocol version"},
191         {529, "Internal hardware failure"},
192         {530, "CAS signaling protocol error."},
193         {531, "failure of a grouping of trunks (e.g. facility failure)."},
194         {532, "Unsupported value(s) in LocalConnectionOptions."},
195         {533, "Response too large."},
196         {534, "Codec negotiation failure."},
197         {535, "Packetization period not supported"},
198         {536, "Unknown or unsupported RestartMethod"},
199         {537, "Unknown or unsupported digit map extension"},
200         {538, "Event/signal parameter error (e.g., missing, erroneous, unsupported, unknown, etc.)"},
201         {539, "Invalid or unsupported command parameter."},
202         {540, "Per endpoint connection limit exceeded."},
203         {541, "Invalid or unsupported LocalConnectionOptions"},
204         {0,   NULL }
205 };
206
207 /* TODO: add/use when tested/have capture to test with */
208 /*
209 static const value_string mgcp_reason_code_vals[] = {
210         {0,   "Endpoint state is normal"},
211         {900, "Endpoint malfunctioning."},
212         {901, "Endpoint taken out-of-service."},
213         {902, "Loss of lower layer connectivity (e.g., downstream sync)."},
214         {903, "QoS resource reservation was lost."},
215         {904, "Manual intervention."},
216         {905, "Facility failure (e.g., DS-0 failure)."},
217         {0,   NULL }
218 };
219 */
220
221
222 /*
223  * Define the trees for mgcp
224  * We need one for MGCP itself, one for the MGCP paramters and one
225  * for each of the dissected parameters
226  */
227 static int ett_mgcp = -1;
228 static int ett_mgcp_param = -1;
229 static int ett_mgcp_param_connectionparam = -1;
230 static int ett_mgcp_param_localconnectionoptions = -1;
231
232 /*
233  * Define the tap for mgcp
234  */
235 static int mgcp_tap = -1;
236
237 /*
238  * Here are the global variables associated with
239  * the various user definable characteristics of the dissection
240  *
241  * MGCP has two kinds of "agents", gateways and callagents.  Callagents
242  * control gateways in a master/slave sort of arrangement.  Since gateways
243  * and callagents have different well known ports and could both
244  * operate under either udp or tcp we have rather a lot of port info to
245  * specify.
246  *
247  * global_mgcp_raw_text determines whether we are going to display
248  * the raw text of the mgcp message, much like the HTTP dissector does.
249  *
250  */
251 static guint global_mgcp_gateway_tcp_port = TCP_PORT_MGCP_GATEWAY;
252 static guint global_mgcp_gateway_udp_port = UDP_PORT_MGCP_GATEWAY;
253 static guint global_mgcp_callagent_tcp_port = TCP_PORT_MGCP_CALLAGENT;
254 static guint global_mgcp_callagent_udp_port = UDP_PORT_MGCP_CALLAGENT;
255 static gboolean global_mgcp_raw_text = FALSE;
256 static gboolean global_mgcp_message_count = FALSE;
257
258 /* Some basic utility functions that are specific to this dissector */
259 static gboolean is_mgcp_verb(tvbuff_t *tvb, gint offset, gint maxlength, const gchar **verb_name);
260 static gboolean is_mgcp_rspcode(tvbuff_t *tvb, gint offset, gint maxlength);
261 static gint tvb_parse_param(tvbuff_t *tvb, gint offset, gint maxlength, int** hf);
262
263 /*
264  * The various functions that either dissect some
265  * subpart of MGCP.  These aren't really proto dissectors but they
266  * are written in the same style.
267  */
268 static void dissect_mgcp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
269                                  proto_tree *mgcp_tree, proto_tree *ti);
270 static void dissect_mgcp_firstline(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
271 static void dissect_mgcp_params(tvbuff_t *tvb, proto_tree *tree);
272 static void dissect_mgcp_connectionparams(proto_tree *parent_tree, tvbuff_t *tvb,
273                                           gint offset, gint param_type_len,
274                                           gint param_val_len);
275 static void dissect_mgcp_localconnectionoptions(proto_tree *parent_tree, tvbuff_t *tvb,
276                                                 gint offset, gint param_type_len,
277                                                 gint param_val_len);
278
279
280 static void mgcp_raw_text_add(tvbuff_t *tvb, proto_tree *tree);
281
282 /*
283  * Some functions which should be moved to a library
284  * as I think that people may find them of general usefulness.
285  */
286 static gint tvb_find_null_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset);
287 static gint tvb_find_dot_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset);
288 static gboolean is_rfc2234_alpha(guint8 c);
289
290 static dissector_handle_t sdp_handle;
291 static dissector_handle_t mgcp_handle;
292 extern void
293 dissect_asciitpkt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
294      dissector_handle_t subdissector_handle);
295 extern guint16 is_asciitpkt(tvbuff_t *tvb);
296
297 /*
298  * Init Hash table stuff
299  */
300
301 typedef struct _mgcp_call_info_key
302 {
303         guint32 transid;
304         conversation_t *conversation;
305 } mgcp_call_info_key;
306
307 static GHashTable *mgcp_calls;
308
309 /* Compare 2 keys */
310 static gint mgcp_call_equal(gconstpointer k1, gconstpointer k2)
311 {
312         const mgcp_call_info_key* key1 = (const mgcp_call_info_key*) k1;
313         const mgcp_call_info_key* key2 = (const mgcp_call_info_key*) k2;
314
315         return (key1->transid == key2->transid &&
316                 key1->conversation == key2->conversation);
317 }
318
319 /* Calculate a hash key */
320 static guint mgcp_call_hash(gconstpointer k)
321 {
322         const mgcp_call_info_key* key = (const mgcp_call_info_key*) k;
323
324         return key->transid  + key->conversation->index;
325 }
326
327
328 /************************************************************************
329  * dissect_mgcp - The dissector for the Media Gateway Control Protocol
330  ************************************************************************/
331 static int dissect_mgcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
332 {
333         gint sectionlen;
334         guint32 num_messages;
335         gint tvb_sectionend,tvb_sectionbegin, tvb_len;
336         proto_tree *mgcp_tree, *ti;
337         const gchar *verb_name = "";
338
339         /* Initialize variables */
340         tvb_sectionend = 0;
341         tvb_sectionbegin = tvb_sectionend;
342         sectionlen = 0;
343         tvb_len = tvb_length(tvb);
344         num_messages = 0;
345         mgcp_tree = NULL;
346         ti = NULL;
347
348         /*
349          * Check to see whether we're really dealing with MGCP by looking
350          * for a valid MGCP verb or response code.  This isn't infallible,
351          * but its cheap and its better than nothing.
352          */
353         if (is_mgcp_verb(tvb,0,tvb_len, &verb_name) || is_mgcp_rspcode(tvb,0,tvb_len))
354         {
355                 /*
356                  * Set the columns now, so that they'll be set correctly if we throw
357                  * an exception.  We can set them later as well....
358                  */
359                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "MGCP");
360                 col_clear(pinfo->cinfo, COL_INFO);
361
362                 /*
363                  * Loop through however many mgcp messages may be stuck in
364                  * this packet using piggybacking
365                  */
366                 do
367                 {
368                         num_messages++;
369                         if (tree)
370                         {
371                                 /* Create our mgcp subtree */
372                                 ti = proto_tree_add_item(tree,proto_mgcp,tvb,0,0, FALSE);
373                                 mgcp_tree = proto_item_add_subtree(ti, ett_mgcp);
374                         }
375
376                         sectionlen = tvb_find_dot_line(tvb, tvb_sectionbegin, -1, &tvb_sectionend);
377                         if (sectionlen != -1)
378                         {
379                                 dissect_mgcp_message(tvb_new_subset(tvb, tvb_sectionbegin,
380                                                                     sectionlen, -1),
381                                                                     pinfo, tree, mgcp_tree,ti);
382                                 tvb_sectionbegin = tvb_sectionend;
383                         }
384                         else
385                         {
386                                 break;
387                         }
388                 } while (tvb_sectionend < tvb_len);
389
390                 if (mgcp_tree)
391                 {
392                         proto_item *tii = proto_tree_add_uint(mgcp_tree, hf_mgcp_messagecount, tvb,
393                                                              0 ,0 , num_messages);
394                         PROTO_ITEM_SET_HIDDEN(tii);
395                 }
396
397                 /*
398                  * Add our column information after dissecting SDP
399                  * in order to prevent the column info changing to reflect the SDP
400                  * (when showing message count)
401                  */
402                 tvb_sectionbegin = 0;
403                 if (global_mgcp_message_count == TRUE )
404                 {
405                         if (num_messages > 1)
406                         {
407                                 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "MGCP (%i messages)",num_messages);
408                         }
409                         else
410                         {
411                                 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "MGCP (%i message)",num_messages);
412                         }
413                 }
414
415                 sectionlen = tvb_find_line_end(tvb, tvb_sectionbegin,-1,
416                                                &tvb_sectionend,FALSE);
417                 col_prepend_fstr(pinfo->cinfo, COL_INFO, "%s",
418                                  tvb_format_text(tvb, tvb_sectionbegin, sectionlen));
419
420                 return tvb_len;
421         }
422
423         return 0;
424 }
425 /************************************************************************
426  * dissect_tpkt_mgcp - The dissector for the ASCII TPKT Media Gateway Control Protocol
427  ************************************************************************/
428 static int dissect_tpkt_mgcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
429 {
430         guint16 ascii_tpkt;
431         int     offset = 0;
432
433         /* Check whether this looks like a ASCII TPKT-encapsulated
434          *  MGCP packet.
435          */
436         ascii_tpkt = is_asciitpkt(tvb);
437
438         if (ascii_tpkt != 1 )
439         {
440                 /*
441                  * It's not a ASCII TPKT packet
442                  * in MGCP
443                  */
444                 offset = dissect_mgcp(tvb, pinfo, tree);
445         }
446         else
447         {
448                 /*
449                  * Dissect ASCII TPKT header
450                  */
451                 dissect_asciitpkt(tvb, pinfo, tree, mgcp_handle);
452                 offset = tvb_length(tvb);
453         }
454
455         return offset;
456 }
457
458 #define MAX_MGCP_MESSAGES_IN_PACKET 5
459 static mgcp_info_t pi_arr[MAX_MGCP_MESSAGES_IN_PACKET];
460 static int pi_current = 0;
461 static mgcp_info_t *mi;
462
463 /* Dissect an individual MGCP message */
464 static void dissect_mgcp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
465                                  proto_tree *mgcp_tree, proto_tree *ti)
466 {
467         /* Declare variables */
468         gint sectionlen;
469         gint tvb_sectionend,tvb_sectionbegin, tvb_len;
470         tvbuff_t *next_tvb;
471         const gchar *verb_name = "";
472
473         /* Initialise stat info for passing to tap */
474         pi_current++;
475         if (pi_current == MAX_MGCP_MESSAGES_IN_PACKET)
476         {
477                 /* Overwrite info in first struct if run out of space... */
478                 pi_current = 0;
479         }
480         mi = &pi_arr[pi_current];
481
482
483         mi->mgcp_type = MGCP_OTHERS;
484         mi->code[0] = '\0';
485         mi->transid = 0;
486         mi->req_time.secs = 0;
487         mi->req_time.nsecs = 0;
488         mi->is_duplicate = FALSE;
489         mi->request_available = FALSE;
490         mi->req_num = 0;
491         mi->endpointId = NULL;
492         mi->observedEvents = NULL;
493         mi->rspcode = 0;
494         mi->signalReq = NULL;
495         mi->hasDigitMap = FALSE;
496
497         /* Initialize variables */
498         tvb_sectionend = 0;
499         tvb_sectionbegin = tvb_sectionend;
500         sectionlen = 0;
501         tvb_len = tvb_length(tvb);
502
503         /*
504          * Check to see whether we're really dealing with MGCP by looking
505          * for a valid MGCP verb or response code.  This isn't infallible,
506          * but its cheap and its better than nothing.
507          */
508         if (is_mgcp_verb(tvb,0,tvb_len,&verb_name) || is_mgcp_rspcode(tvb,0,tvb_len))
509         {
510                 /* dissect first line */
511                 tvb_sectionbegin = 0;
512                 tvb_sectionend = tvb_sectionbegin;
513                 sectionlen = tvb_find_line_end(tvb,0,-1,&tvb_sectionend,FALSE);
514                 if (sectionlen > 0)
515                 {
516                         dissect_mgcp_firstline(tvb_new_subset(tvb, tvb_sectionbegin,
517                                                sectionlen,-1), pinfo,
518                                                mgcp_tree);
519                 }
520                 tvb_sectionbegin = tvb_sectionend;
521
522                 /* Dissect params */
523                 if (tvb_sectionbegin < tvb_len)
524                 {
525                         sectionlen = tvb_find_null_line(tvb, tvb_sectionbegin, -1,
526                                                         &tvb_sectionend);
527                         if (sectionlen > 0)
528                         {
529                                 dissect_mgcp_params(tvb_new_subset(tvb, tvb_sectionbegin, sectionlen, -1),
530                                                                    mgcp_tree);
531                                 tvb_sectionbegin = tvb_sectionend;
532                         }
533                 }
534
535                 /* Set the mgcp payload length correctly so we don't include any
536                    encapsulated SDP */
537                 sectionlen = tvb_sectionend;
538                 proto_item_set_len(ti,sectionlen);
539
540                 /* Display the raw text of the mgcp message if desired */
541
542                 /* Do we want to display the raw text of our MGCP packet? */
543                 if (global_mgcp_raw_text)
544                 {
545                         if (tree)
546                                 mgcp_raw_text_add(tvb, mgcp_tree);
547                 }
548
549                 /* Dissect sdp payload */
550                 if (tvb_sectionend < tvb_len)
551                 {
552                         next_tvb = tvb_new_subset_remaining(tvb, tvb_sectionend);
553                         call_dissector(sdp_handle, next_tvb, pinfo, tree);
554                 }
555         }
556 }
557
558
559 /*
560  * Add the raw text of the message to the dissect tree if appropriate
561  * preferences are specified.
562  */
563 static void mgcp_raw_text_add(tvbuff_t *tvb, proto_tree *tree)
564 {
565         gint tvb_linebegin,tvb_lineend,tvb_len,linelen;
566
567         tvb_linebegin = 0;
568         tvb_len = tvb_length(tvb);
569
570         do
571         {
572                 tvb_find_line_end(tvb,tvb_linebegin,-1,&tvb_lineend,FALSE);
573                 linelen = tvb_lineend - tvb_linebegin;
574                 proto_tree_add_text(tree, tvb, tvb_linebegin, linelen, "%s",
575                                     tvb_format_text(tvb, tvb_linebegin, linelen));
576                 tvb_linebegin = tvb_lineend;
577         } while (tvb_lineend < tvb_len);
578 }
579
580 /* Discard and init any state we've saved */
581 static void mgcp_init_protocol(void)
582 {
583         if (mgcp_calls != NULL)
584         {
585                 g_hash_table_destroy(mgcp_calls);
586                 mgcp_calls = NULL;
587         }
588
589         mgcp_calls = g_hash_table_new(mgcp_call_hash, mgcp_call_equal);
590 }
591
592 /* Register all the bits needed with the filtering engine */
593 void proto_register_mgcp(void)
594 {
595     static hf_register_info hf[] =
596     {
597         { &hf_mgcp_req,
598           { "Request", "mgcp.req", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
599             "True if MGCP request", HFILL }},
600         { &hf_mgcp_rsp,
601           { "Response", "mgcp.rsp", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
602             "TRUE if MGCP response", HFILL }},
603         { &hf_mgcp_req_frame,
604           { "Request Frame", "mgcp.reqframe", FT_FRAMENUM, BASE_NONE, NULL, 0,
605             NULL, HFILL }},
606         { &hf_mgcp_rsp_frame,
607           { "Response Frame", "mgcp.rspframe", FT_FRAMENUM, BASE_NONE, NULL, 0,
608             NULL, HFILL }},
609         { &hf_mgcp_time,
610           { "Time from request", "mgcp.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0,
611             "Timedelta between Request and Response", HFILL }},
612         { &hf_mgcp_req_verb,
613           { "Verb", "mgcp.req.verb", FT_STRING, BASE_NONE, NULL, 0x0,
614             "Name of the verb", HFILL }},
615         { &hf_mgcp_req_endpoint,
616           { "Endpoint", "mgcp.req.endpoint", FT_STRING, BASE_NONE, NULL, 0x0,
617             "Endpoint referenced by the message", HFILL }},
618         { &hf_mgcp_transid,
619           { "Transaction ID", "mgcp.transid", FT_STRING, BASE_NONE, NULL, 0x0,
620             "Transaction ID of this message", HFILL }},
621         { &hf_mgcp_version,
622           { "Version", "mgcp.version", FT_STRING, BASE_NONE, NULL, 0x0,
623             "MGCP Version", HFILL }},
624         { &hf_mgcp_rsp_rspcode,
625           { "Response Code", "mgcp.rsp.rspcode", FT_UINT32, BASE_DEC, VALS(mgcp_return_code_vals), 0x0,
626             NULL, HFILL }},
627         { &hf_mgcp_rsp_rspstring,
628           { "Response String", "mgcp.rsp.rspstring", FT_STRING, BASE_NONE, NULL, 0x0,
629             NULL, HFILL }},
630         { &hf_mgcp_params,
631           { "Parameters", "mgcp.params", FT_NONE, BASE_NONE, NULL, 0x0,
632             "MGCP parameters", HFILL }},
633         { &hf_mgcp_param_rspack,
634           { "ResponseAck (K)", "mgcp.param.rspack", FT_STRING, BASE_NONE, NULL, 0x0,
635             "Response Ack", HFILL }},
636         { &hf_mgcp_param_bearerinfo,
637           { "BearerInformation (B)", "mgcp.param.bearerinfo", FT_STRING, BASE_NONE, NULL, 0x0,
638             "Bearer Information", HFILL }},
639         { &hf_mgcp_param_callid,
640           { "CallId (C)", "mgcp.param.callid", FT_STRING, BASE_NONE, NULL, 0x0,
641             "Call Id", HFILL }},
642         { &hf_mgcp_param_connectionid,
643           {"ConnectionIdentifier (I)", "mgcp.param.connectionid", FT_STRING, BASE_NONE, NULL, 0x0,
644             "Connection Identifier", HFILL }},
645         { &hf_mgcp_param_secondconnectionid,
646           { "SecondConnectionID (I2)", "mgcp.param.secondconnectionid", FT_STRING, BASE_NONE, NULL, 0x0,
647             "Second Connection Identifier", HFILL }},
648         { &hf_mgcp_param_notifiedentity,
649           { "NotifiedEntity (N)", "mgcp.param.notifiedentity", FT_STRING, BASE_NONE, NULL, 0x0,
650             "Notified Entity", HFILL }},
651         { &hf_mgcp_param_requestid,
652           { "RequestIdentifier (X)", "mgcp.param.requestid", FT_STRING, BASE_NONE, NULL, 0x0,
653             "Request Identifier", HFILL }},
654         { &hf_mgcp_param_localconnoptions,
655           { "LocalConnectionOptions (L)", "mgcp.param.localconnectionoptions", FT_STRING, BASE_NONE, NULL, 0x0,
656             "Local Connection Options", HFILL }},
657         { &hf_mgcp_param_localconnoptions_p,
658           { "Packetization period (p)", "mgcp.param.localconnectionoptions.p", FT_UINT32, BASE_DEC, NULL, 0x0,
659             "Packetization period", HFILL }},
660         { &hf_mgcp_param_localconnoptions_a,
661           { "Codecs (a)", "mgcp.param.localconnectionoptions.a", FT_STRING, BASE_NONE, NULL, 0x0,
662             "Codecs", HFILL }},
663         { &hf_mgcp_param_localconnoptions_s,
664           { "Silence Suppression (s)", "mgcp.param.localconnectionoptions.s", FT_STRING, BASE_NONE, NULL, 0x0,
665             "Silence Suppression", HFILL }},
666         { &hf_mgcp_param_localconnoptions_e,
667           { "Echo Cancellation (e)", "mgcp.param.localconnectionoptions.e", FT_STRING, BASE_NONE, NULL, 0x0,
668             "Echo Cancellation", HFILL }},
669         { &hf_mgcp_param_localconnoptions_scrtp,
670           { "RTP ciphersuite (sc-rtp)", "mgcp.param.localconnectionoptions.scrtp", FT_STRING, BASE_NONE, NULL, 0x0,
671             "RTP ciphersuite", HFILL }},
672         { &hf_mgcp_param_localconnoptions_scrtcp,
673           { "RTCP ciphersuite (sc-rtcp)", "mgcp.param.localconnectionoptions.scrtcp", FT_STRING, BASE_NONE, NULL, 0x0,
674             "RTCP ciphersuite", HFILL }},
675         { &hf_mgcp_param_localconnoptions_b,
676           { "Bandwidth (b)", "mgcp.param.localconnectionoptions.b", FT_STRING, BASE_NONE, NULL, 0x0,
677             "Bandwidth", HFILL }},
678         { &hf_mgcp_param_localconnoptions_esccd,
679           { "Content Destination (es-ccd)", "mgcp.param.localconnectionoptions.esccd", FT_STRING, BASE_NONE, NULL, 0x0,
680             "Content Destination", HFILL }},
681         { &hf_mgcp_param_localconnoptions_escci,
682           { "Content Identifier (es-cci)", "mgcp.param.localconnectionoptions.escci", FT_STRING, BASE_NONE, NULL, 0x0,
683             "Content Identifier", HFILL }},
684         { &hf_mgcp_param_localconnoptions_dqgi,
685           { "D-QoS GateID (dq-gi)", "mgcp.param.localconnectionoptions.dqgi", FT_STRING, BASE_NONE, NULL, 0x0,
686             "D-QoS GateID", HFILL }},
687         { &hf_mgcp_param_localconnoptions_dqrd,
688           { "D-QoS Reserve Destination (dq-rd)", "mgcp.param.localconnectionoptions.dqrd", FT_STRING, BASE_NONE, NULL, 0x0,
689             "D-QoS Reserve Destination", HFILL }},
690         { &hf_mgcp_param_localconnoptions_dqri,
691           { "D-QoS Resource ID (dq-ri)", "mgcp.param.localconnectionoptions.dqri", FT_STRING, BASE_NONE, NULL, 0x0,
692             "D-QoS Resource ID", HFILL }},
693         { &hf_mgcp_param_localconnoptions_dqrr,
694           { "D-QoS Resource Reservation (dq-rr)", "mgcp.param.localconnectionoptions.dqrr", FT_STRING, BASE_NONE, NULL, 0x0,
695             "D-QoS Resource Reservation", HFILL }},
696         { &hf_mgcp_param_localconnoptions_k,
697           { "Encryption Key (k)", "mgcp.param.localconnectionoptions.k", FT_STRING, BASE_NONE, NULL, 0x0,
698             "Encryption Key", HFILL }},
699         { &hf_mgcp_param_localconnoptions_gc,
700           { "Gain Control (gc)", "mgcp.param.localconnectionoptions.gc", FT_UINT32, BASE_DEC, NULL, 0x0,
701             "Gain Control", HFILL }},
702         { &hf_mgcp_param_localconnoptions_fmtp,
703           { "Media Format (fmtp)", "mgcp.param.localconnectionoptions.fmtp", FT_STRING, BASE_NONE, NULL, 0x0,
704             "Media Format", HFILL }},
705         { &hf_mgcp_param_localconnoptions_nt,
706           { "Network Type (nt)", "mgcp.param.localconnectionoptions.nt", FT_STRING, BASE_NONE, NULL, 0x0,
707             "Network Type", HFILL }},
708         { &hf_mgcp_param_localconnoptions_ofmtp,
709           { "Optional Media Format (o-fmtp)", "mgcp.param.localconnectionoptions.ofmtp", FT_STRING, BASE_NONE, NULL, 0x0,
710             "Optional Media Format", HFILL }},
711         { &hf_mgcp_param_localconnoptions_r,
712           { "Resource Reservation (r)", "mgcp.param.localconnectionoptions.r", FT_STRING, BASE_NONE, NULL, 0x0,
713             "Resource Reservation", HFILL }},
714         { &hf_mgcp_param_localconnoptions_t,
715           { "Type of Service (r)", "mgcp.param.localconnectionoptions.t", FT_STRING, BASE_NONE, NULL, 0x0,
716             "Type of Service", HFILL }},
717         { &hf_mgcp_param_localconnoptions_rcnf,
718           { "Reservation Confirmation (r-cnf)", "mgcp.param.localconnectionoptions.rcnf", FT_STRING, BASE_NONE, NULL, 0x0,
719             "Reservation Confirmation", HFILL }},
720         { &hf_mgcp_param_localconnoptions_rdir,
721           { "Reservation Direction (r-dir)", "mgcp.param.localconnectionoptions.rdir", FT_STRING, BASE_NONE, NULL, 0x0,
722             "Reservation Direction", HFILL }},
723         { &hf_mgcp_param_localconnoptions_rsh,
724           { "Resource Sharing (r-sh)", "mgcp.param.localconnectionoptions.rsh", FT_STRING, BASE_NONE, NULL, 0x0,
725             "Resource Sharing", HFILL }},
726         { &hf_mgcp_param_connectionmode,
727           { "ConnectionMode (M)", "mgcp.param.connectionmode", FT_STRING, BASE_NONE, NULL, 0x0,
728             "Connection Mode", HFILL }},
729         { &hf_mgcp_param_reqevents,
730           { "RequestedEvents (R)", "mgcp.param.reqevents", FT_STRING, BASE_NONE, NULL, 0x0,
731             "Requested Events", HFILL }},
732         { &hf_mgcp_param_signalreq,
733           { "SignalRequests (S)", "mgcp.param.signalreq", FT_STRING, BASE_NONE, NULL, 0x0,
734             "Signal Request", HFILL }},
735         { &hf_mgcp_param_restartmethod,
736           { "RestartMethod (RM)", "mgcp.param.restartmethod", FT_STRING, BASE_NONE, NULL, 0x0,
737             "Restart Method", HFILL }},
738         { &hf_mgcp_param_restartdelay,
739           { "RestartDelay (RD)", "mgcp.param.restartdelay", FT_STRING, BASE_NONE, NULL, 0x0,
740             "Restart Delay", HFILL }},
741         { &hf_mgcp_param_digitmap,
742           { "DigitMap (D)", "mgcp.param.digitmap", FT_STRING, BASE_NONE, NULL, 0x0,
743             "Digit Map", HFILL }},
744         { &hf_mgcp_param_observedevent,
745           { "ObservedEvents (O)", "mgcp.param.observedevents", FT_STRING, BASE_NONE, NULL, 0x0,
746             "Observed Events", HFILL }},
747         { &hf_mgcp_param_connectionparam,
748           { "ConnectionParameters (P)", "mgcp.param.connectionparam", FT_STRING, BASE_NONE, NULL, 0x0,
749             "Connection Parameters", HFILL }},
750         { &hf_mgcp_param_connectionparam_ps,
751           { "Packets sent (PS)", "mgcp.param.connectionparam.ps", FT_UINT32, BASE_DEC, NULL, 0x0,
752             "Packets sent (P:PS)", HFILL }},
753         { &hf_mgcp_param_connectionparam_os,
754           { "Octets sent (OS)", "mgcp.param.connectionparam.os", FT_UINT32, BASE_DEC, NULL, 0x0,
755             "Octets sent (P:OS)", HFILL }},
756         { &hf_mgcp_param_connectionparam_pr,
757           { "Packets received (PR)", "mgcp.param.connectionparam.pr", FT_UINT32, BASE_DEC, NULL, 0x0,
758             "Packets received (P:PR)", HFILL }},
759         { &hf_mgcp_param_connectionparam_or,
760           { "Octets received (OR)", "mgcp.param.connectionparam.or", FT_UINT32, BASE_DEC, NULL, 0x0,
761             "Octets received (P:OR)", HFILL }},
762         { &hf_mgcp_param_connectionparam_pl,
763           { "Packets lost (PL)", "mgcp.param.connectionparam.pl", FT_UINT32, BASE_DEC, NULL, 0x0,
764             "Packets lost (P:PL)", HFILL }},
765         { &hf_mgcp_param_connectionparam_ji,
766           { "Jitter (JI)", "mgcp.param.connectionparam.ji", FT_UINT32, BASE_DEC, NULL, 0x0,
767             "Average inter-packet arrival jitter in milliseconds (P:JI)", HFILL }},
768         { &hf_mgcp_param_connectionparam_la,
769           { "Latency (LA)", "mgcp.param.connectionparam.la", FT_UINT32, BASE_DEC, NULL, 0x0,
770             "Average latency in milliseconds (P:LA)", HFILL }},
771         { &hf_mgcp_param_connectionparam_pcrps,
772           { "Remote Packets sent (PC/RPS)", "mgcp.param.connectionparam.pcrps", FT_UINT32, BASE_DEC, NULL, 0x0,
773             "Remote Packets sent (P:PC/RPS)", HFILL }},
774         { &hf_mgcp_param_connectionparam_pcros,
775           { "Remote Octets sent (PC/ROS)", "mgcp.param.connectionparam.pcros", FT_UINT32, BASE_DEC, NULL, 0x0,
776             "Remote Octets sent (P:PC/ROS)", HFILL }},
777         { &hf_mgcp_param_connectionparam_pcrpl,
778           { "Remote Packets lost (PC/RPL)", "mgcp.param.connectionparam.pcrpl", FT_UINT32, BASE_DEC, NULL, 0x0,
779             "Remote Packets lost (P:PC/RPL)", HFILL }},
780         { &hf_mgcp_param_connectionparam_pcrji,
781           { "Remote Jitter (PC/RJI)", "mgcp.param.connectionparam.pcrji", FT_UINT32, BASE_DEC, NULL, 0x0,
782             "Remote Jitter (P:PC/RJI)", HFILL }},
783         { &hf_mgcp_param_connectionparam_x,
784           { "Vendor Extension", "mgcp.param.connectionparam.x", FT_STRING, BASE_NONE, NULL, 0x0,
785             "Vendor Extension (P:X-*)", HFILL }},
786         { &hf_mgcp_param_reasoncode,
787           { "ReasonCode (E)", "mgcp.param.reasoncode", FT_STRING, BASE_NONE, NULL, 0x0,
788             "Reason Code", HFILL }},
789         { &hf_mgcp_param_eventstates,
790           { "EventStates (ES)", "mgcp.param.eventstates", FT_STRING, BASE_NONE, NULL, 0x0,
791             "Event States", HFILL }},
792         { &hf_mgcp_param_specificendpoint,
793           { "SpecificEndpointID (Z)", "mgcp.param.specificendpointid", FT_STRING, BASE_NONE, NULL, 0x0,
794             "Specific Endpoint ID", HFILL }},
795         { &hf_mgcp_param_secondendpointid,
796           { "SecondEndpointID (Z2)", "mgcp.param.secondendpointid", FT_STRING, BASE_NONE, NULL, 0x0,
797             "Second Endpoint ID", HFILL }},
798         { &hf_mgcp_param_reqinfo,
799           { "RequestedInfo (F)", "mgcp.param.reqinfo", FT_STRING, BASE_NONE, NULL, 0x0,
800             "Requested Info", HFILL }},
801         { &hf_mgcp_param_quarantinehandling,
802           { "QuarantineHandling (Q)", "mgcp.param.quarantinehandling", FT_STRING, BASE_NONE, NULL, 0x0,
803             "Quarantine Handling", HFILL }},
804         { &hf_mgcp_param_detectedevents,
805           { "DetectedEvents (T)", "mgcp.param.detectedevents", FT_STRING, BASE_NONE, NULL, 0x0,
806             "Detected Events", HFILL }},
807         { &hf_mgcp_param_capabilities,
808           { "Capabilities (A)", "mgcp.param.capabilities", FT_STRING, BASE_NONE, NULL, 0x0,
809             "Capabilities", HFILL }},
810         { &hf_mgcp_param_maxmgcpdatagram,
811           {"MaxMGCPDatagram (MD)", "mgcp.param.maxmgcpdatagram", FT_STRING, BASE_NONE, NULL, 0x0,
812            "Maximum MGCP Datagram size", HFILL }},
813         { &hf_mgcp_param_packagelist,
814           {"PackageList (PL)", "mgcp.param.packagelist", FT_STRING, BASE_NONE, NULL, 0x0,
815            "Package List", HFILL }},
816         { &hf_mgcp_param_extension,
817           { "Extension Parameter (non-critical)", "mgcp.param.extension", FT_STRING, BASE_NONE, NULL, 0x0,
818             "Extension Parameter", HFILL }},
819         { &hf_mgcp_param_extension_critical,
820           { "Extension Parameter (critical)", "mgcp.param.extensioncritical", FT_STRING, BASE_NONE, NULL, 0x0,
821             "Critical Extension Parameter", HFILL }},
822         { &hf_mgcp_param_invalid,
823           { "Invalid Parameter", "mgcp.param.invalid", FT_STRING, BASE_NONE, NULL, 0x0,
824             NULL, HFILL }},
825         { &hf_mgcp_messagecount,
826           { "MGCP Message Count", "mgcp.messagecount", FT_UINT32, BASE_DEC, NULL, 0x0,
827             "Number of MGCP message in a packet", HFILL }},
828         { &hf_mgcp_dup,
829           { "Duplicate Message", "mgcp.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
830             NULL, HFILL }},
831         { &hf_mgcp_req_dup,
832           { "Duplicate Request", "mgcp.req.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
833             NULL, HFILL }},
834         { &hf_mgcp_req_dup_frame,
835           { "Original Request Frame", "mgcp.req.dup.frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
836             "Frame containing original request", HFILL }},
837         { &hf_mgcp_rsp_dup,
838           { "Duplicate Response", "mgcp.rsp.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
839             NULL, HFILL }},
840         { &hf_mgcp_rsp_dup_frame,
841           { "Original Response Frame", "mgcp.rsp.dup.frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
842             "Frame containing original response", HFILL }},
843     };
844
845     static gint *ett[] =
846     {
847         &ett_mgcp,
848         &ett_mgcp_param,
849         &ett_mgcp_param_connectionparam,
850         &ett_mgcp_param_localconnectionoptions
851     };
852
853     module_t *mgcp_module;
854
855     /* Register protocol */
856     proto_mgcp = proto_register_protocol("Media Gateway Control Protocol", "MGCP", "mgcp");
857     proto_register_field_array(proto_mgcp, hf, array_length(hf));
858     proto_register_subtree_array(ett, array_length(ett));
859     register_init_routine(&mgcp_init_protocol);
860
861     new_register_dissector("mgcp", dissect_mgcp, proto_mgcp);
862
863     /* Register our configuration options */
864     mgcp_module = prefs_register_protocol(proto_mgcp, proto_reg_handoff_mgcp);
865
866     prefs_register_uint_preference(mgcp_module, "tcp.gateway_port",
867                                    "MGCP Gateway TCP Port",
868                                    "Set the UDP port for gateway messages "
869                                    "(if other than the default of 2427)",
870                                    10, &global_mgcp_gateway_tcp_port);
871
872     prefs_register_uint_preference(mgcp_module, "udp.gateway_port",
873                                    "MGCP Gateway UDP Port",
874                                    "Set the TCP port for gateway messages "
875                                    "(if other than the default of 2427)",
876                                    10, &global_mgcp_gateway_udp_port);
877
878     prefs_register_uint_preference(mgcp_module, "tcp.callagent_port",
879                                    "MGCP Callagent TCP Port",
880                                    "Set the TCP port for callagent messages "
881                                    "(if other than the default of 2727)",
882                                    10, &global_mgcp_callagent_tcp_port);
883
884     prefs_register_uint_preference(mgcp_module, "udp.callagent_port",
885                                    "MGCP Callagent UDP Port",
886                                    "Set the UDP port for callagent messages "
887                                    "(if other than the default of 2727)",
888                                    10, &global_mgcp_callagent_udp_port);
889
890
891     prefs_register_bool_preference(mgcp_module, "display_raw_text",
892                                   "Display raw text for MGCP message",
893                                   "Specifies that the raw text of the "
894                                   "MGCP message should be displayed "
895                                   "instead of (or in addition to) the "
896                                   "dissection tree",
897                                   &global_mgcp_raw_text);
898
899     prefs_register_obsolete_preference(mgcp_module, "display_dissect_tree");
900
901     prefs_register_bool_preference(mgcp_module, "display_mgcp_message_count",
902                                    "Display the number of MGCP messages",
903                                    "Display the number of MGCP messages "
904                                    "found in a packet in the protocol column.",
905                                    &global_mgcp_message_count);
906
907     mgcp_tap = register_tap("mgcp");
908 }
909
910 /* The registration hand-off routine */
911 void proto_reg_handoff_mgcp(void)
912 {
913         static gboolean mgcp_prefs_initialized = FALSE;
914         static dissector_handle_t mgcp_tpkt_handle;
915         /*
916          * Variables to allow for proper deletion of dissector registration when
917          * the user changes port from the gui.
918          */
919         static guint gateway_tcp_port;
920         static guint gateway_udp_port;
921         static guint callagent_tcp_port;
922         static guint callagent_udp_port;
923
924         if (!mgcp_prefs_initialized)
925         {
926                 /* Get a handle for the SDP dissector. */
927                 sdp_handle = find_dissector("sdp");
928                 mgcp_handle = new_create_dissector_handle(dissect_mgcp, proto_mgcp);
929                 mgcp_tpkt_handle = new_create_dissector_handle(dissect_tpkt_mgcp, proto_mgcp);
930                 mgcp_prefs_initialized = TRUE;
931         }
932         else
933         {
934                 dissector_delete_uint("tcp.port", gateway_tcp_port, mgcp_tpkt_handle);
935                 dissector_delete_uint("udp.port", gateway_udp_port, mgcp_handle);
936                 dissector_delete_uint("tcp.port", callagent_tcp_port, mgcp_tpkt_handle);
937                 dissector_delete_uint("udp.port", callagent_udp_port, mgcp_handle);
938         }
939
940         /* Set our port number for future use */
941         gateway_tcp_port = global_mgcp_gateway_tcp_port;
942         gateway_udp_port = global_mgcp_gateway_udp_port;
943
944         callagent_tcp_port = global_mgcp_callagent_tcp_port;
945         callagent_udp_port = global_mgcp_callagent_udp_port;
946
947         dissector_add_uint("tcp.port", global_mgcp_gateway_tcp_port, mgcp_tpkt_handle);
948         dissector_add_uint("udp.port", global_mgcp_gateway_udp_port, mgcp_handle);
949         dissector_add_uint("tcp.port", global_mgcp_callagent_tcp_port, mgcp_tpkt_handle);
950         dissector_add_uint("udp.port", global_mgcp_callagent_udp_port, mgcp_handle);
951 }
952
953 /*
954  * is_mgcp_verb - A function for determining whether there is a
955  *                MGCP verb at offset in tvb
956  *
957  * Parameter:
958  * tvb - The tvbuff in which we are looking for an MGCP verb
959  * offset - The offset in tvb at which we are looking for a MGCP verb
960  * maxlength - The maximum distance from offset we may look for the
961  *             characters that make up a MGCP verb.
962  * verb_name - The name for the verb code found (output)
963  *
964  * Return: TRUE if there is an MGCP verb at offset in tvb, otherwise FALSE
965  */
966 static gboolean is_mgcp_verb(tvbuff_t *tvb, gint offset, gint maxlength, const gchar **verb_name)
967 {
968         int returnvalue = FALSE;
969         gchar word[5];
970
971         /* Read the string into 'word' and see if it looks like the start of a verb */
972         if ((maxlength >= 4) && tvb_get_nstringz0(tvb, offset, sizeof(word), word))
973         {
974                 if (((g_ascii_strncasecmp(word, "EPCF", 4) == 0) && (*verb_name = "EndpointConfiguration")) ||
975                     ((g_ascii_strncasecmp(word, "CRCX", 4) == 0) && (*verb_name = "CreateConnection")) ||
976                     ((g_ascii_strncasecmp(word, "MDCX", 4) == 0) && (*verb_name = "ModifyConnection")) ||
977                     ((g_ascii_strncasecmp(word, "DLCX", 4) == 0) && (*verb_name = "DeleteConnection")) ||
978                     ((g_ascii_strncasecmp(word, "RQNT", 4) == 0) && (*verb_name = "NotificationRequest")) ||
979                     ((g_ascii_strncasecmp(word, "NTFY", 4) == 0) && (*verb_name = "Notify")) ||
980                     ((g_ascii_strncasecmp(word, "AUEP", 4) == 0) && (*verb_name = "AuditEndpoint")) ||
981                     ((g_ascii_strncasecmp(word, "AUCX", 4) == 0) && (*verb_name = "AuditConnection")) ||
982                     ((g_ascii_strncasecmp(word, "RSIP", 4) == 0) && (*verb_name = "RestartInProgress")) ||
983                     ((g_ascii_strncasecmp(word, "MESG", 4) == 0) && (*verb_name = "Message")) ||
984                     (word[0] == 'X' && is_rfc2234_alpha(word[1]) && is_rfc2234_alpha(word[2]) &&
985                                        is_rfc2234_alpha(word[3]) && (*verb_name = "*Experimental*")))
986                 {
987                         returnvalue = TRUE;
988                 }
989         }
990
991         /* May be whitespace after verb code - anything else is an error.. */
992         if (returnvalue && maxlength >= 5)
993         {
994                 char next = tvb_get_guint8(tvb,4);
995                 if ((next != ' ') && (next != '\t'))
996                 {
997                         returnvalue = FALSE;
998                 }
999         }
1000
1001         return returnvalue;
1002 }
1003
1004 /*
1005  * is_mgcp_rspcode - A function for determining whether something which
1006  *                   looks roughly like a MGCP response code (3-digit number)
1007  *                   is at 'offset' in tvb
1008  *
1009  * Parameters:
1010  * tvb - The tvbuff in which we are looking for an MGCP response code
1011  * offset - The offset in tvb at which we are looking for a MGCP response code
1012  * maxlength - The maximum distance from offset we may look for the
1013  *             characters that make up a MGCP response code.
1014  *
1015  * Return: TRUE if there is an MGCP response code at offset in tvb,
1016  *         otherwise FALSE
1017  */
1018 static gboolean is_mgcp_rspcode(tvbuff_t *tvb, gint offset, gint maxlength)
1019 {
1020         int returnvalue = FALSE;
1021         guint8 word[4];
1022
1023         /* Do 1st 3 characters look like digits? */
1024         if (maxlength >= 3)
1025         {
1026                 tvb_get_nstringz0(tvb, offset, sizeof(word), word);
1027                 if (isdigit(word[0]) && isdigit(word[1]) && isdigit(word[2]))
1028                 {
1029                         returnvalue = TRUE;
1030                 }
1031         }
1032
1033         /* Maybe some white space after the 3rd digit - anything else is an error */
1034         if (returnvalue && maxlength >= 4)
1035         {
1036                 char next = tvb_get_guint8(tvb, 3);
1037                 if ((next != ' ') && (next != '\t'))
1038                 {
1039                         returnvalue = FALSE;
1040                 }
1041         }
1042
1043         return returnvalue;
1044 }
1045
1046 /*
1047  * is_rfc2234_alpha - Indicates whether the character c is an alphabetical
1048  *                    character.  This function is used instead of
1049  *                    isalpha because isalpha may deviate from the rfc2234
1050  *                    definition of ALPHA in some locales.
1051  *
1052  * Parameter:
1053  * c - The character being checked for being an alphabetical character.
1054  *
1055  * Return: TRUE if c is an upper or lower case alphabetical character,
1056  *         FALSE otherwise.
1057  */
1058 static gboolean is_rfc2234_alpha(guint8 c)
1059 {
1060         return ((c <= 'Z' && c >= 'A' ) || (c <= 'z' && c >= 'a'));
1061 }
1062
1063
1064 /*
1065  * tvb_parse_param - Parse the MGCP param into a type and a value.
1066  *
1067  * Parameters:
1068  * tvb - The tvbuff containing the MGCP param we are to parse.
1069  * offset - The offset in tvb at which we will begin looking for a
1070  *          MGCP parameter to parse.
1071  * len - The maximum distance from offset in tvb that we can look for
1072  *       an MGCP parameter to parse.
1073  * hf - The place to write a pointer to the integer representing the
1074  *      header field associated with the MGCP parameter parsed.
1075  *
1076  * Returns: The offset in tvb where the value of the MGCP parameter
1077  *          begins.
1078  */
1079 static gint tvb_parse_param(tvbuff_t* tvb, gint offset, gint len, int** hf)
1080 {
1081         gint returnvalue = -1, tvb_current_offset,counter;
1082         guint8 tempchar, plus_minus;
1083         gchar **buf;
1084
1085         tvb_current_offset = offset;
1086         *hf = NULL;
1087         buf=NULL;
1088
1089         if (len > 0)
1090         {
1091                 tempchar = tvb_get_guint8(tvb,tvb_current_offset);
1092
1093                 switch (tempchar)
1094                 {
1095                         case 'K':
1096                                 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1097                                 {
1098                                         *hf = &hf_mgcp_param_invalid;
1099                                         break;
1100                                 }
1101                                 *hf = &hf_mgcp_param_rspack;
1102                                 break;
1103                         case 'B':
1104                                 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1105                                 {
1106                                         *hf = &hf_mgcp_param_invalid;
1107                                         break;
1108                                 }
1109                                 *hf = &hf_mgcp_param_bearerinfo;
1110                                 break;
1111                         case 'C':
1112                                 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1113                                 {
1114                                         *hf = &hf_mgcp_param_invalid;
1115                                         break;
1116                                 }
1117                                 *hf = &hf_mgcp_param_callid;
1118                                 break;
1119                         case 'I':
1120                                 tvb_current_offset++;
1121                                 if (len > (tvb_current_offset - offset) &&
1122                                    (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1123                                 {
1124                                         *hf = &hf_mgcp_param_connectionid;
1125                                         tvb_current_offset--;
1126                                 }
1127                                 else
1128                                         if (tempchar == '2')
1129                                 {
1130                                         *hf = &hf_mgcp_param_secondconnectionid;
1131                                 }
1132                                 break;
1133                         case 'N':
1134                                 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1135                                 {
1136                                         *hf = &hf_mgcp_param_invalid;
1137                                         break;
1138                                 }
1139                                 *hf = &hf_mgcp_param_notifiedentity;
1140                                 break;
1141                         case 'X':
1142                                 /* Move past 'X' */
1143                                 tvb_current_offset++;
1144
1145                                 /* X: is RequestIdentifier */
1146                                 if (len > (tvb_current_offset - offset) &&
1147                                    (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1148                                 {
1149                                         *hf = &hf_mgcp_param_requestid;
1150                                         tvb_current_offset--;
1151                                 }
1152
1153                                 /* X+...: or X-....: are vendor extension parameters */
1154                                 else
1155                                 if (len > (tvb_current_offset - offset) &&
1156                                     ((plus_minus = tvb_get_guint8(tvb,tvb_current_offset)) == '-' ||
1157                                      (plus_minus == '+')))
1158                                 {
1159                                         /* Move past + or - */
1160                                         tvb_current_offset++;
1161
1162                                         /* Keep going, through possible vendor param name */
1163                                         for (counter = 1;
1164                                             ((len > (counter + tvb_current_offset-offset)) &&
1165                                             (is_rfc2234_alpha(tempchar = tvb_get_guint8(tvb, tvb_current_offset+counter)) ||
1166                                              isdigit(tempchar))) ;
1167                                              counter++);
1168
1169                                         if (tempchar == ':')
1170                                         {
1171                                                 /* Looks like a valid vendor param name */
1172                                                 tvb_current_offset += counter;
1173                                                 switch (plus_minus)
1174                                                 {
1175                                                         case '+':
1176                                                                 *hf = &hf_mgcp_param_extension_critical;
1177                                                                 break;
1178                                                         case '-':
1179                                                                 *hf = &hf_mgcp_param_extension;
1180                                                                 break;
1181                                                 }
1182                                         }
1183                                 }
1184                                 break;
1185                         case 'L':
1186                                 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1187                                 {
1188                                         *hf = &hf_mgcp_param_invalid;
1189                                         break;
1190                                 }
1191                                 *hf = &hf_mgcp_param_localconnoptions;
1192                                 break;
1193                         case 'M':
1194                                 tvb_current_offset++;
1195                                 if (len > (tvb_current_offset - offset) &&
1196                                    (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1197                                 {
1198                                         *hf = &hf_mgcp_param_connectionmode;
1199                                         tvb_current_offset--;
1200                                 }
1201                                 else
1202                                 if (tempchar == 'D')
1203                                 {
1204                                         *hf = &hf_mgcp_param_maxmgcpdatagram;
1205                                 }
1206                                 break;
1207                         case 'R':
1208                                 tvb_current_offset++;
1209                                 if (len > (tvb_current_offset - offset) &&
1210                                     (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1211                                 {
1212                                         *hf = &hf_mgcp_param_reqevents;
1213                                         tvb_current_offset--;
1214                                 }
1215                                 else
1216                                 if ( tempchar == 'M')
1217                                 {
1218                                         *hf = &hf_mgcp_param_restartmethod;
1219                                 }
1220                                 else
1221                                 if (tempchar == 'D')
1222                                 {
1223                                         *hf = &hf_mgcp_param_restartdelay;
1224                                 }
1225                                 break;
1226                         case 'S':
1227                                 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1228                                 {
1229                                         *hf = &hf_mgcp_param_invalid;
1230                                         break;
1231                                 }
1232                                 *hf = &hf_mgcp_param_signalreq;
1233                                 buf = &(mi->signalReq);
1234                                 break;
1235                         case 'D':
1236                                 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1237                                 {
1238                                         *hf = &hf_mgcp_param_invalid;
1239                                         break;
1240                                 }
1241                                 *hf = &hf_mgcp_param_digitmap;
1242                                 mi->hasDigitMap = TRUE;
1243                                 break;
1244                         case 'O':
1245                                 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1246                                 {
1247                                         *hf = &hf_mgcp_param_invalid;
1248                                         break;
1249                                 }
1250                                 *hf = &hf_mgcp_param_observedevent;
1251                                 buf = &(mi->observedEvents);
1252                                 break;
1253                         case 'P':
1254                                 tvb_current_offset++;
1255                                 if (len > (tvb_current_offset - offset) &&
1256                                     (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1257                                 {
1258                                         *hf = &hf_mgcp_param_connectionparam;
1259                                         tvb_current_offset--;
1260                                 }
1261                                 else
1262                                 if ( tempchar == 'L')
1263                                 {
1264                                         *hf = &hf_mgcp_param_packagelist;
1265                                 }
1266                                 break;
1267                         case 'E':
1268                                 tvb_current_offset++;
1269                                 if (len > (tvb_current_offset - offset) &&
1270                                     (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1271                                 {
1272                                         *hf = &hf_mgcp_param_reasoncode;
1273                                         tvb_current_offset--;
1274                                 }
1275                                 else
1276                                 if ( tempchar == 'S')
1277                                 {
1278                                         *hf = &hf_mgcp_param_eventstates;
1279                                 }
1280                                 break;
1281                         case 'Z':
1282                                 tvb_current_offset++;
1283                                 if (len > (tvb_current_offset - offset) &&
1284                                     (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1285                                 {
1286                                         *hf = &hf_mgcp_param_specificendpoint;
1287                                         tvb_current_offset--;
1288                                 }
1289                                 else
1290                                 if (tempchar == '2')
1291                                 {
1292                                         *hf = &hf_mgcp_param_secondendpointid;
1293                                 }
1294                                 break;
1295                         case 'F':
1296                                 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1297                                 {
1298                                         *hf = &hf_mgcp_param_invalid;
1299                                         break;
1300                                 }
1301                                 *hf = &hf_mgcp_param_reqinfo;
1302                                 break;
1303                         case 'Q':
1304                                 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1305                                 {
1306                                         *hf = &hf_mgcp_param_invalid;
1307                                         break;
1308                                 }
1309                                 *hf = &hf_mgcp_param_quarantinehandling;
1310                                 break;
1311                         case 'T':
1312                                 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1313                                 {
1314                                         *hf = &hf_mgcp_param_invalid;
1315                                         break;
1316                                 }
1317                                 *hf = &hf_mgcp_param_detectedevents;
1318                                 break;
1319                         case 'A':
1320                                 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1321                                 {
1322                                         *hf = &hf_mgcp_param_invalid;
1323                                         break;
1324                                 }
1325                                 *hf = &hf_mgcp_param_capabilities;
1326                                 break;
1327
1328                         default:
1329                                 *hf = &hf_mgcp_param_invalid;
1330                                 break;
1331                 }
1332
1333                 /* Move to (hopefully) the colon */
1334                 tvb_current_offset++;
1335
1336                 /* Add a recognised parameter type if we have one */
1337                 if (*hf != NULL && len > (tvb_current_offset - offset) &&
1338                     tvb_get_guint8(tvb,tvb_current_offset) == ':')
1339                 {
1340                         tvb_current_offset++;
1341                         tvb_current_offset = tvb_skip_wsp(tvb,tvb_current_offset, (len - tvb_current_offset + offset));
1342                         returnvalue = tvb_current_offset;
1343
1344                        /* set the observedEvents or signalReq used in Voip Calls analysis */
1345                        if (buf != NULL) {
1346                                *buf = tvb_get_ephemeral_string(tvb, tvb_current_offset, (len - tvb_current_offset + offset));
1347                        }
1348                 }
1349         }
1350         else
1351         {
1352                 /* Was an empty line */
1353                 *hf = &hf_mgcp_param_invalid;
1354         }
1355
1356         /* For these types, show the whole line */
1357         if ((*hf == &hf_mgcp_param_invalid) ||
1358             (*hf == &hf_mgcp_param_extension) || (*hf == &hf_mgcp_param_extension_critical))
1359         {
1360                 returnvalue = offset;
1361         }
1362
1363         return returnvalue;
1364 }
1365
1366
1367 /*
1368  * dissect_mgcp_firstline - Dissects the firstline of an MGCP message.
1369  *                          Adds the appropriate headers fields to
1370  *                          tree for the dissection of the first line
1371  *                          of an MGCP message.
1372  *
1373  * Parameters:
1374  * tvb - The tvb containing the first line of an MGCP message.  This
1375  *       tvb is presumed to ONLY contain the first line of the MGCP
1376  *       message.
1377  * pinfo - The packet info for the packet.  This is not really used
1378  *         by this function but is passed through so as to retain the
1379  *         style of a dissector.
1380  * tree - The tree from which to hang the structured information parsed
1381  *        from the first line of the MGCP message.
1382  */
1383 static void dissect_mgcp_firstline(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1384 {
1385         gint tvb_current_offset,tvb_previous_offset,tvb_len,tvb_current_len;
1386         gint tokennum, tokenlen;
1387         proto_item* hidden_item;
1388         char *transid = NULL;
1389         char *code = NULL;
1390         char *endpointId = NULL;
1391         mgcp_type_t mgcp_type = MGCP_OTHERS;
1392         conversation_t* conversation;
1393         mgcp_call_info_key mgcp_call_key;
1394         mgcp_call_info_key *new_mgcp_call_key = NULL;
1395         mgcp_call_t *mgcp_call = NULL;
1396         nstime_t delta;
1397         gint rspcode = 0;
1398         const gchar *verb_description = "";
1399         char code_with_verb[64] = "";  /* To fit "<4-letter-code> (<longest-verb>)" */
1400
1401         static address null_address = { AT_NONE, 0, NULL };
1402         tvb_previous_offset = 0;
1403         tvb_len = tvb_length(tvb);
1404         tvb_current_len = tvb_len;
1405         tvb_current_offset = tvb_previous_offset;
1406         mi->is_duplicate = FALSE;
1407         mi->request_available = FALSE;
1408
1409         if (tree)
1410         {
1411                 tokennum = 0;
1412
1413                 do
1414                 {
1415                         tvb_current_len = tvb_length_remaining(tvb,tvb_previous_offset);
1416                         tvb_current_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_current_len, ' ');
1417                         if (tvb_current_offset == -1)
1418                         {
1419                                 tvb_current_offset = tvb_len;
1420                                 tokenlen = tvb_current_len;
1421                         }
1422                         else
1423                         {
1424                                 tokenlen = tvb_current_offset - tvb_previous_offset;
1425                         }
1426                         if (tokennum == 0)
1427                         {
1428                                 if (tokenlen > 4)
1429                                         THROW(ReportedBoundsError);
1430                                 code = tvb_format_text(tvb,tvb_previous_offset,tokenlen);
1431                                 g_strlcpy(mi->code,code,5);
1432                                 if (is_mgcp_verb(tvb,tvb_previous_offset,tvb_current_len,&verb_description))
1433                                 {
1434                                         mgcp_type = MGCP_REQUEST;
1435                                         if (verb_description != NULL)
1436                                         {
1437                                                 /* Can show verb along with code if known */
1438                                                 g_snprintf(code_with_verb, 64, "%s (%s)", code, verb_description);
1439                                         }
1440
1441                                         proto_tree_add_string_format(tree, hf_mgcp_req_verb, tvb,
1442                                                                      tvb_previous_offset, tokenlen,
1443                                                                      code, "%s",
1444                                                                      strlen(code_with_verb) ? code_with_verb : code);
1445                                 }
1446                                 else
1447                                 if (is_mgcp_rspcode(tvb,tvb_previous_offset,tvb_current_len))
1448                                 {
1449                                         mgcp_type = MGCP_RESPONSE;
1450                                         rspcode = atoi(code);
1451                                         mi->rspcode = rspcode;
1452                                         proto_tree_add_uint(tree,hf_mgcp_rsp_rspcode, tvb,
1453                                                             tvb_previous_offset, tokenlen, rspcode);
1454                                 }
1455                                 else
1456                                 {
1457                                         break;
1458                                 }
1459                         }
1460                         if (tokennum == 1)
1461                         {
1462                                 transid = tvb_format_text(tvb,tvb_previous_offset,tokenlen);
1463                                 /* XXX - what if this isn't a valid text string? */
1464                                 mi->transid = atol(transid);
1465                                 proto_tree_add_string(tree, hf_mgcp_transid, tvb,
1466                                                       tvb_previous_offset, tokenlen, transid);
1467                         }
1468                         if (tokennum == 2)
1469                         {
1470                                 if (mgcp_type == MGCP_REQUEST)
1471                                 {
1472                                         endpointId = tvb_format_text(tvb, tvb_previous_offset,tokenlen);
1473                                         mi->endpointId = ep_strdup(endpointId);
1474                                         proto_tree_add_string(tree,hf_mgcp_req_endpoint, tvb,
1475                                                               tvb_previous_offset, tokenlen, endpointId);
1476                                 }
1477                                 else
1478                                 if (mgcp_type == MGCP_RESPONSE)
1479                                 {
1480                                         if (tvb_current_offset < tvb_len)
1481                                         {
1482                                                 tokenlen = tvb_find_line_end(tvb, tvb_previous_offset,
1483                                                                              -1, &tvb_current_offset, FALSE);
1484                                         }
1485                                         else
1486                                         {
1487                                                 tokenlen = tvb_current_len;
1488                                         }
1489                                         proto_tree_add_string(tree, hf_mgcp_rsp_rspstring, tvb,
1490                                                               tvb_previous_offset, tokenlen,
1491                                                               tvb_format_text(tvb, tvb_previous_offset,
1492                                                               tokenlen));
1493                                         break;
1494                                 }
1495                         }
1496
1497                         if ((tokennum == 3 && mgcp_type == MGCP_REQUEST))
1498                         {
1499                                 if (tvb_current_offset < tvb_len )
1500                                 {
1501                                         tokenlen = tvb_find_line_end(tvb, tvb_previous_offset,
1502                                                                      -1, &tvb_current_offset,FALSE);
1503                                 }
1504                                 else
1505                                 {
1506                                         tokenlen = tvb_current_len;
1507                                 }
1508                                 proto_tree_add_string(tree,hf_mgcp_version, tvb,
1509                                                       tvb_previous_offset, tokenlen,
1510                                                       tvb_format_text(tvb,tvb_previous_offset,
1511                                                       tokenlen));
1512                                 break;
1513                         }
1514                         if (tvb_current_offset < tvb_len)
1515                         {
1516                                 tvb_previous_offset = tvb_skip_wsp(tvb, tvb_current_offset,
1517                                                                    tvb_current_len);
1518                         }
1519                         tokennum++;
1520                 } while (tvb_current_offset < tvb_len && tvb_previous_offset < tvb_len && tokennum <= 3);
1521
1522                 switch (mgcp_type)
1523                 {
1524                         case MGCP_RESPONSE:
1525                                 hidden_item = proto_tree_add_boolean(tree, hf_mgcp_rsp, tvb, 0, 0, TRUE);
1526                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
1527                                 /* Check for MGCP response.  A response must match a call that
1528                                    we've seen, and the response must be sent to the same
1529                                    port and address that the call came from, and must
1530                                    come from the port to which the call was sent.
1531
1532                                    If the transport is connection-oriented (we check, for
1533                                    now, only for "pinfo->ptype" of PT_TCP), we take
1534                                    into account the address from which the call was sent
1535                                    and the address to which the call was sent, because
1536                                    the addresses of the two endpoints should be the same
1537                                    for all calls and replies.
1538
1539                                    If the transport is connectionless, we don't worry
1540                                    about the address to which the call was sent and from
1541                                    which the reply was sent, because there's no
1542                                    guarantee that the reply will come from the address
1543                                    to which the call was sent. */
1544                                 if (pinfo->ptype == PT_TCP)
1545                                 {
1546                                         conversation = find_conversation(pinfo->fd->num, &pinfo->src,
1547                                                                          &pinfo->dst, pinfo->ptype, pinfo->srcport,
1548                                                                          pinfo->destport, 0);
1549                                 }
1550                                 else
1551                                 {
1552                                         /* XXX - can we just use NO_ADDR_B?  Unfortunately,
1553                                          * you currently still have to pass a non-null
1554                                          * pointer for the second address argument even
1555                                          * if you do that.
1556                                          */
1557                                         conversation = find_conversation(pinfo->fd->num, &null_address,
1558                                                                          &pinfo->dst, pinfo->ptype, pinfo->srcport,
1559                                                                          pinfo->destport, 0);
1560                                 }
1561                                 if (conversation != NULL)
1562                                 {
1563                                         /* Look only for matching request, if
1564                                            matching conversation is available. */
1565                                         mgcp_call_key.transid = mi->transid;
1566                                         mgcp_call_key.conversation = conversation;
1567                                         mgcp_call = g_hash_table_lookup(mgcp_calls, &mgcp_call_key);
1568                                         if (mgcp_call)
1569                                         {
1570                                                 /* Indicate the frame to which this is a reply. */
1571                                                 if (mgcp_call->req_num)
1572                                                 {
1573                                                         proto_item* item;
1574                                                         mi->request_available = TRUE;
1575                                                         mgcp_call->responded = TRUE;
1576                                                         mi->req_num = mgcp_call->req_num;
1577                                                         g_strlcpy(mi->code,mgcp_call->code,5);
1578                                                         item = proto_tree_add_uint_format(tree, hf_mgcp_req_frame,
1579                                                                                           tvb, 0, 0, mgcp_call->req_num,
1580                                                                                           "This is a response to a request in frame %u",
1581                                                                                           mgcp_call->req_num);
1582                                                         PROTO_ITEM_SET_GENERATED(item);
1583                                                         nstime_delta(&delta, &pinfo->fd->abs_ts, &mgcp_call->req_time);
1584                                                         item = proto_tree_add_time(tree, hf_mgcp_time, tvb, 0, 0, &delta);
1585                                                         PROTO_ITEM_SET_GENERATED(item);
1586                                                 }
1587
1588                                                 if (mgcp_call->rsp_num == 0)
1589                                                 {
1590                                                         /* We have not yet seen a response to that call, so
1591                                                            this must be the first response; remember its
1592                                                            frame number. */
1593                                                         mgcp_call->rsp_num = pinfo->fd->num;
1594                                                 }
1595                                                 else
1596                                                 {
1597                                                         /* We have seen a response to this call - but was it
1598                                                            *this* response? (disregard provisional responses) */
1599                                                         if ((mgcp_call->rsp_num != pinfo->fd->num) &&
1600                                                             (mi->rspcode >= 200) &&
1601                                                             (mi->rspcode == mgcp_call->rspcode))
1602                                                         {
1603                                                                 /* No, so it's a duplicate response. Mark it as such. */
1604                                                                 mi->is_duplicate = TRUE;
1605                                                                 col_append_fstr(pinfo->cinfo, COL_INFO,
1606                                                                                 ", Duplicate Response %u",
1607                                                                                 mi->transid);
1608                                                                 if (tree)
1609                                                                 {
1610                                                                         proto_item* item;
1611                                                                         item = proto_tree_add_uint(tree, hf_mgcp_dup, tvb, 0,0, mi->transid);
1612                                                                         PROTO_ITEM_SET_HIDDEN(item);
1613                                                                         item = proto_tree_add_uint(tree, hf_mgcp_rsp_dup,
1614                                                                                                    tvb, 0, 0, mi->transid);
1615                                                                         PROTO_ITEM_SET_GENERATED(item);
1616                                                                         item = proto_tree_add_uint(tree, hf_mgcp_rsp_dup_frame,
1617                                                                                                    tvb, 0, 0, mgcp_call->rsp_num);
1618                                                                         PROTO_ITEM_SET_GENERATED(item);
1619                                                                 }
1620                                                         }
1621                                                 }
1622                                                 /* Now store the response code (after comparison above) */
1623                                                 mgcp_call->rspcode = mi->rspcode;
1624                                         }
1625                                 }
1626                                 break;
1627                         case MGCP_REQUEST:
1628                                 hidden_item = proto_tree_add_boolean(tree, hf_mgcp_req, tvb, 0, 0, TRUE);
1629                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
1630                                 /* Keep track of the address and port whence the call came,
1631                                  * and the port to which the call is being sent, so that
1632                                  * we can match up calls with replies.
1633                                  *
1634                                  * If the transport is connection-oriented (we check, for
1635                                  * now, only for "pinfo->ptype" of PT_TCP), we take
1636                                  * into account the address from which the call was sent
1637                                  * and the address to which the call was sent, because
1638                                  * the addresses of the two endpoints should be the same
1639                                  * for all calls and replies.
1640                                  *
1641                                  * If the transport is connectionless, we don't worry
1642                                  * about the address to which the call was sent and from
1643                                  * which the reply was sent, because there's no
1644                                  * guarantee that the reply will come from the address
1645                                  * to which the call was sent.
1646                                  */
1647                                 if (pinfo->ptype == PT_TCP)
1648                                 {
1649                                         conversation = find_conversation(pinfo->fd->num, &pinfo->src,
1650                                                                          &pinfo->dst, pinfo->ptype, pinfo->srcport,
1651                                                                          pinfo->destport, 0);
1652                                 }
1653                                 else
1654                                 {
1655                                         /*
1656                                          * XXX - can we just use NO_ADDR_B?  Unfortunately,
1657                                          * you currently still have to pass a non-null
1658                                          * pointer for the second address argument even
1659                                          * if you do that.
1660                                          */
1661                                         conversation = find_conversation(pinfo->fd->num, &pinfo->src,
1662                                                                          &null_address, pinfo->ptype, pinfo->srcport,
1663                                                                          pinfo->destport, 0);
1664                                 }
1665                                 if (conversation == NULL)
1666                                 {
1667                                         /* It's not part of any conversation - create a new one. */
1668                                         if (pinfo->ptype == PT_TCP)
1669                                         {
1670                                                 conversation = conversation_new(pinfo->fd->num, &pinfo->src,
1671                                                                                 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1672                                                                                 pinfo->destport, 0);
1673                                         }
1674                                         else
1675                                         {
1676                                                 conversation = conversation_new(pinfo->fd->num, &pinfo->src,
1677                                                                                 &null_address, pinfo->ptype, pinfo->srcport,
1678                                                                                 pinfo->destport, 0);
1679                                         }
1680                                 }
1681
1682                                 /* Prepare the key data */
1683                                 mgcp_call_key.transid = mi->transid;
1684                                 mgcp_call_key.conversation = conversation;
1685
1686                                 /* Look up the request */
1687                                 mgcp_call = g_hash_table_lookup(mgcp_calls, &mgcp_call_key);
1688                                 if (mgcp_call != NULL)
1689                                 {
1690                                         /* We've seen a request with this TRANSID, with the same
1691                                            source and destination, before - but was it
1692                                            *this* request? */
1693                                         if (pinfo->fd->num != mgcp_call->req_num)
1694                                         {
1695                                                 /* No, so it's a duplicate request. Mark it as such. */
1696                                                 mi->is_duplicate = TRUE;
1697                                                 mi->req_num = mgcp_call->req_num;
1698                                                 col_append_fstr(pinfo->cinfo, COL_INFO,
1699                                                                 ", Duplicate Request %u",
1700                                                                 mi->transid);
1701                                                 if (tree)
1702                                                 {
1703                                                         proto_item* item;
1704                                                         item = proto_tree_add_uint(tree, hf_mgcp_dup, tvb, 0,0, mi->transid);
1705                                                         PROTO_ITEM_SET_HIDDEN(item);
1706                                                         item = proto_tree_add_uint(tree, hf_mgcp_req_dup, tvb, 0,0, mi->transid);
1707                                                         PROTO_ITEM_SET_GENERATED(item);
1708                                                         item = proto_tree_add_uint(tree, hf_mgcp_req_dup_frame, tvb, 0,0, mi->req_num);
1709                                                         PROTO_ITEM_SET_GENERATED(item);
1710                                                 }
1711                                         }
1712                                 }
1713                                 else
1714                                 {
1715                                         /* Prepare the value data.
1716                                            "req_num" and "rsp_num" are frame numbers;
1717                                            frame numbers are 1-origin, so we use 0
1718                                            to mean "we don't yet know in which frame
1719                                            the reply for this call appears". */
1720                                         new_mgcp_call_key = se_alloc(sizeof(*new_mgcp_call_key));
1721                                         *new_mgcp_call_key = mgcp_call_key;
1722                                         mgcp_call = se_alloc(sizeof(*mgcp_call));
1723                                         mgcp_call->req_num = pinfo->fd->num;
1724                                         mgcp_call->rsp_num = 0;
1725                                         mgcp_call->transid = mi->transid;
1726                                         mgcp_call->responded = FALSE;
1727                                         mgcp_call->req_time=pinfo->fd->abs_ts;
1728                                         g_strlcpy(mgcp_call->code,mi->code,5);
1729
1730                                         /* Store it */
1731                                         g_hash_table_insert(mgcp_calls, new_mgcp_call_key, mgcp_call);
1732                                 }
1733                                 if (mgcp_call->rsp_num)
1734                                 {
1735                                         proto_item* item = proto_tree_add_uint_format(tree, hf_mgcp_rsp_frame,
1736                                                                                       tvb, 0, 0, mgcp_call->rsp_num,
1737                                                                                       "The response to this request is in frame %u",
1738                                                                                       mgcp_call->rsp_num);
1739                                         PROTO_ITEM_SET_GENERATED(item);
1740                                 }
1741                                 break;
1742                         default:
1743                                 break;
1744                 }
1745
1746                 mi->mgcp_type = mgcp_type;
1747                 if (mgcp_call)
1748                 {
1749                         mi->req_time.secs=mgcp_call->req_time.secs;
1750                         mi->req_time.nsecs=mgcp_call->req_time.nsecs;
1751                 }
1752         }
1753
1754         tap_queue_packet(mgcp_tap, pinfo, mi);
1755 }
1756
1757 /*
1758  * dissect_mgcp_params - Dissects the parameters of an MGCP message.
1759  *                       Adds the appropriate headers fields to
1760  *                       tree for the dissection of the parameters
1761  *                       of an MGCP message.
1762  *
1763  * Parameters:
1764  * tvb - The tvb containing the parameters of an MGCP message.  This
1765  *       tvb is presumed to ONLY contain the part of the MGCP
1766  *       message which contains the MGCP parameters.
1767  * tree - The tree from which to hang the structured information parsed
1768  *        from the parameters of the MGCP message.
1769  */
1770 static void dissect_mgcp_params(tvbuff_t *tvb, proto_tree *tree)
1771 {
1772         int linelen, tokenlen, *my_param;
1773         gint tvb_lineend, tvb_linebegin, tvb_len, old_lineend;
1774         gint tvb_tokenbegin;
1775         proto_tree *mgcp_param_ti, *mgcp_param_tree;
1776
1777         tvb_len = tvb_length(tvb);
1778         tvb_linebegin = 0;
1779         tvb_lineend = tvb_linebegin;
1780
1781         if (tree)
1782         {
1783                 mgcp_param_ti = proto_tree_add_item(tree, hf_mgcp_params, tvb,
1784                                                     tvb_linebegin, tvb_len, ENC_NA);
1785                 proto_item_set_text(mgcp_param_ti, "Parameters");
1786                 mgcp_param_tree = proto_item_add_subtree(mgcp_param_ti, ett_mgcp_param);
1787
1788                 /* Parse the parameters */
1789                 while (tvb_lineend < tvb_len)
1790                 {
1791                         old_lineend = tvb_lineend;
1792                         linelen = tvb_find_line_end(tvb, tvb_linebegin, -1,&tvb_lineend,FALSE);
1793                         tvb_tokenbegin = tvb_parse_param(tvb, tvb_linebegin, linelen, &my_param);
1794
1795                         if (my_param)
1796                         {
1797                                 if (*my_param == hf_mgcp_param_connectionparam)
1798                                 {
1799                                         tokenlen = tvb_find_line_end(tvb,tvb_tokenbegin,-1,&tvb_lineend,FALSE);
1800                                         dissect_mgcp_connectionparams(mgcp_param_tree, tvb, tvb_linebegin,
1801                                                                       tvb_tokenbegin - tvb_linebegin, tokenlen);
1802                                 }
1803                                 else
1804                                 if (*my_param == hf_mgcp_param_localconnoptions)
1805                                 {
1806                                         tokenlen = tvb_find_line_end(tvb,tvb_tokenbegin,-1,&tvb_lineend,FALSE);
1807                                         dissect_mgcp_localconnectionoptions(mgcp_param_tree, tvb, tvb_linebegin,
1808                                                                             tvb_tokenbegin - tvb_linebegin, tokenlen);
1809                                 }
1810                                 else
1811                                 {
1812                                         tokenlen = tvb_find_line_end(tvb,tvb_tokenbegin,-1,&tvb_lineend,FALSE);
1813                                         proto_tree_add_string(mgcp_param_tree,*my_param, tvb,
1814                                                               tvb_linebegin, linelen,
1815                                                               tvb_format_text(tvb,tvb_tokenbegin, tokenlen));
1816                                 }
1817                         }
1818
1819                         tvb_linebegin = tvb_lineend;
1820                         /* Its a infinite loop if we didn't advance (or went backwards) */
1821                         if (old_lineend >= tvb_lineend)
1822                         {
1823                                 THROW(ReportedBoundsError);
1824                         }
1825                 }
1826         }
1827 }
1828
1829 /* Dissect the connection params */
1830 static void
1831 dissect_mgcp_connectionparams(proto_tree *parent_tree, tvbuff_t *tvb, gint offset, gint param_type_len, gint param_val_len)
1832 {
1833         proto_tree *tree = parent_tree;
1834         proto_item *item = NULL;
1835
1836         gchar *tokenline = NULL;
1837         gchar **tokens = NULL;
1838         gchar **typval = NULL;
1839         guint i = 0;
1840         guint tokenlen = 0;
1841         int hf_uint = -1;
1842         int hf_string = -1;
1843
1844         if (parent_tree)
1845         {
1846                 item = proto_tree_add_item(parent_tree, hf_mgcp_param_connectionparam, tvb, offset, param_type_len+param_val_len, ENC_ASCII|ENC_NA);
1847                 tree = proto_item_add_subtree(item, ett_mgcp_param_connectionparam);
1848         }
1849
1850         /* The P: line */
1851         offset += param_type_len; /* skip the P: */
1852         tokenline = tvb_get_ephemeral_string(tvb, offset, param_val_len);
1853
1854         /* Split into type=value pairs separated by comma */
1855         tokens = ep_strsplit(tokenline, ",", -1);
1856
1857         for (i = 0; tokens[i] != NULL; i++)
1858         {
1859                 tokenlen = (int)strlen(tokens[i]);
1860                 typval = ep_strsplit(tokens[i], "=", 2);
1861                 if ((typval[0] != NULL) && (typval[1] != NULL))
1862                 {
1863                         if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PS"))
1864                         {
1865                                 hf_uint = hf_mgcp_param_connectionparam_ps;
1866                         }
1867                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "OS"))
1868                         {
1869                                 hf_uint = hf_mgcp_param_connectionparam_os;
1870                         }
1871                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PR"))
1872                         {
1873                                 hf_uint = hf_mgcp_param_connectionparam_pr;
1874                         }
1875                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "OR"))
1876                         {
1877                                 hf_uint = hf_mgcp_param_connectionparam_or;
1878                         }
1879                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PL"))
1880                         {
1881                                 hf_uint = hf_mgcp_param_connectionparam_pl;
1882                         }
1883                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "JI"))
1884                         {
1885                                 hf_uint = hf_mgcp_param_connectionparam_ji;
1886                         }
1887                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "LA"))
1888                         {
1889                                 hf_uint = hf_mgcp_param_connectionparam_la;
1890                         }
1891                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PC/RPS"))
1892                         {
1893                                 hf_uint = hf_mgcp_param_connectionparam_pcrps;
1894                         } else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PC/ROS"))
1895                         {
1896                                 hf_uint = hf_mgcp_param_connectionparam_pcros;
1897                         }
1898                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PC/RPL"))
1899                         {
1900                                 hf_uint = hf_mgcp_param_connectionparam_pcrpl;
1901                         }
1902                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PC/RJI"))
1903                         {
1904                                 hf_uint = hf_mgcp_param_connectionparam_pcrji;
1905                         }
1906                         else if (!g_ascii_strncasecmp(g_strstrip(typval[0]), "X-", 2))
1907                         {
1908                                 hf_string = hf_mgcp_param_connectionparam_x;
1909                         }
1910                         else
1911                         {
1912                                 hf_uint = -1;
1913                                 hf_string = -1;
1914                         }
1915
1916                         if (tree)
1917                         {
1918                                 if (hf_uint != -1)
1919                                 {
1920                                         proto_tree_add_uint(tree, hf_uint, tvb, offset, tokenlen, atol(typval[1]));
1921                                 }
1922                                 else if (hf_string != -1)
1923                                 {
1924                                         proto_tree_add_string(tree, hf_string, tvb, offset, tokenlen, g_strstrip(typval[1]));
1925                                 }
1926                                 else
1927                                 {
1928                                         proto_tree_add_text(tree, tvb, offset, tokenlen, "Unknown parameter: %s", tokens[i]);
1929                                 }
1930                         }
1931                 }
1932                 else if (tree)
1933                 {
1934                         proto_tree_add_text(tree, tvb, offset, tokenlen, "Malformed parameter: %s", tokens[i]);
1935                 }
1936                 offset += tokenlen + 1; /* 1 extra for the delimiter */
1937         }
1938
1939 }
1940
1941 /* Dissect the local connection option */
1942 static void
1943 dissect_mgcp_localconnectionoptions(proto_tree *parent_tree, tvbuff_t *tvb, gint offset, gint param_type_len, gint param_val_len)
1944 {
1945         proto_tree *tree = parent_tree;
1946         proto_item *item = NULL;
1947
1948         gchar *tokenline = NULL;
1949         gchar **tokens = NULL;
1950         gchar **typval = NULL;
1951         guint i = 0;
1952         guint tokenlen = 0;
1953         int hf_uint = -1;
1954         int hf_string = -1;
1955
1956         if (parent_tree)
1957         {
1958                 item = proto_tree_add_item(parent_tree, hf_mgcp_param_localconnoptions, tvb, offset, param_type_len+param_val_len, ENC_ASCII|ENC_NA);
1959                 tree = proto_item_add_subtree(item, ett_mgcp_param_localconnectionoptions);
1960         }
1961
1962         /* The L: line */
1963         offset += param_type_len; /* skip the L: */
1964         tokenline = tvb_get_ephemeral_string(tvb, offset, param_val_len);
1965
1966         /* Split into type=value pairs separated by comma */
1967         tokens = ep_strsplit(tokenline, ",", -1);
1968         for (i = 0; tokens[i] != NULL; i++)
1969         {
1970                 hf_uint = -1;
1971                 hf_string = -1;
1972
1973                 tokenlen = (int)strlen(tokens[i]);
1974                 typval = ep_strsplit(tokens[i], ":", 2);
1975                 if ((typval[0] != NULL) && (typval[1] != NULL))
1976                 {
1977                         if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "p"))
1978                         {
1979                                 hf_uint = hf_mgcp_param_localconnoptions_p;
1980                         }
1981                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "a"))
1982                         {
1983                                 hf_string = hf_mgcp_param_localconnoptions_a;
1984                         }
1985                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "s"))
1986                         {
1987                                 hf_string = hf_mgcp_param_localconnoptions_s;
1988                         }
1989                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "e"))
1990                         {
1991                                 hf_string = hf_mgcp_param_localconnoptions_e;
1992                         }
1993                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "sc-rtp"))
1994                         {
1995                                 hf_string = hf_mgcp_param_localconnoptions_scrtp;
1996                         }
1997                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "sc-rtcp"))
1998                         {
1999                                 hf_string = hf_mgcp_param_localconnoptions_scrtcp;
2000                         }
2001                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "b"))
2002                         {
2003                                 hf_string = hf_mgcp_param_localconnoptions_b;
2004                         }
2005                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "es-ccd"))
2006                         {
2007                                 hf_string = hf_mgcp_param_localconnoptions_esccd;
2008                         }
2009                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "es-cci"))
2010                         {
2011                                 hf_string = hf_mgcp_param_localconnoptions_escci;
2012                         }
2013                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "dq-gi"))
2014                         {
2015                                 hf_string = hf_mgcp_param_localconnoptions_dqgi;
2016                         }
2017                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "dq-rd"))
2018                         {
2019                                 hf_string = hf_mgcp_param_localconnoptions_dqrd;
2020                         }
2021                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "dq-ri"))
2022                         {
2023                                 hf_string = hf_mgcp_param_localconnoptions_dqri;
2024                         }
2025                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "dq-rr"))
2026                         {
2027                                 hf_string = hf_mgcp_param_localconnoptions_dqrr;
2028                         }
2029                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "k"))
2030                         {
2031                                 hf_string = hf_mgcp_param_localconnoptions_k;
2032                         }
2033                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "gc"))
2034                         {
2035                                 hf_uint = hf_mgcp_param_localconnoptions_gc;
2036                         }
2037                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "fmtp"))
2038                         {
2039                                 hf_string = hf_mgcp_param_localconnoptions_fmtp;
2040                         }
2041                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "nt"))
2042                         {
2043                                 hf_string = hf_mgcp_param_localconnoptions_nt;
2044                         }
2045                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "o-fmtp"))
2046                         {
2047                                 hf_string = hf_mgcp_param_localconnoptions_ofmtp;
2048                         }
2049                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "r"))
2050                         {
2051                                 hf_string = hf_mgcp_param_localconnoptions_r;
2052                         }
2053                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "t"))
2054                         {
2055                                 hf_string = hf_mgcp_param_localconnoptions_t;
2056                         }
2057                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "r-cnf"))
2058                         {
2059                                 hf_string = hf_mgcp_param_localconnoptions_rcnf;
2060                         }
2061                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "r-dir"))
2062                         {
2063                                 hf_string = hf_mgcp_param_localconnoptions_rdir;
2064                         }
2065                         else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "r-sh"))
2066                         {
2067                                 hf_string = hf_mgcp_param_localconnoptions_rsh;
2068                         }
2069                         else
2070                         {
2071                                 hf_uint = -1;
2072                                 hf_string = -1;
2073                         }
2074
2075                         /* Add item */
2076                         if (tree)
2077                         {
2078                                 if (hf_uint != -1)
2079                                 {
2080                                         proto_tree_add_uint(tree, hf_uint, tvb, offset, tokenlen, atol(typval[1]));
2081                                 }
2082                                 else if (hf_string != -1)
2083                                 {
2084                                         proto_tree_add_string(tree, hf_string, tvb, offset, tokenlen, g_strstrip(typval[1]));
2085                                 }
2086                                 else
2087                                 {
2088                                         proto_tree_add_text(tree, tvb, offset, tokenlen, "Unknown parameter: %s", tokens[i]);
2089                                 }
2090                         }
2091                 }
2092                 else if (tree)
2093                 {
2094                         proto_tree_add_text(tree, tvb, offset, tokenlen, "Malformed parameter: %s", tokens[i]);
2095                 }
2096                 offset += tokenlen + 1; /* 1 extra for the delimiter */
2097         }
2098 }
2099
2100
2101
2102 /*
2103  * tvb_find_null_line - Returns the length from offset to the first null
2104  *                      line found (a null line is a line that begins
2105  *                      with a CR or LF.  The offset to the first character
2106  *                      after the null line is written into the gint pointed
2107  *                      to by next_offset.
2108  *
2109  * Parameters:
2110  * tvb - The tvbuff in which we are looking for a null line.
2111  * offset - The offset in tvb at which we will begin looking for
2112  *          a null line.
2113  * len - The maximum distance from offset in tvb that we will look for
2114  *       a null line.  If it is -1 we will look to the end of the buffer.
2115  *
2116  * next_offset - The location to write the offset of first character
2117  *               FOLLOWING the null line.
2118  *
2119  * Returns: The length from offset to the first character BEFORE
2120  *          the null line..
2121  */
2122 static gint tvb_find_null_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset)
2123 {
2124         gint tvb_lineend,tvb_current_len,tvb_linebegin,maxoffset;
2125         guint tempchar;
2126
2127         tvb_linebegin = offset;
2128         tvb_lineend = tvb_linebegin;
2129
2130         /* Simple setup to allow for the traditional -1 search to the end of the tvbuff */
2131         if (len != -1)
2132         {
2133                 tvb_current_len = len;
2134         }
2135         else
2136         {
2137                 tvb_current_len = tvb_length_remaining(tvb,offset);
2138         }
2139
2140         maxoffset = (tvb_current_len - 1) + offset;
2141
2142         /* Loop around until we either find a line begining with a carriage return
2143            or newline character or until we hit the end of the tvbuff. */
2144         do
2145         {
2146                 tvb_linebegin = tvb_lineend;
2147                 tvb_current_len = tvb_length_remaining(tvb,tvb_linebegin);
2148                 tvb_find_line_end(tvb, tvb_linebegin, tvb_current_len, &tvb_lineend,FALSE);
2149                 tempchar = tvb_get_guint8(tvb,tvb_linebegin);
2150         } while (tempchar != '\r' && tempchar != '\n' && tvb_lineend <= maxoffset);
2151
2152
2153         *next_offset = tvb_lineend;
2154
2155         if (tvb_lineend <= maxoffset)
2156         {
2157                 tvb_current_len = tvb_linebegin - offset;
2158         }
2159         else
2160         {
2161                 tvb_current_len = tvb_length_remaining(tvb,offset);
2162         }
2163
2164         return tvb_current_len;
2165 }
2166
2167 /*
2168  * tvb_find_dot_line -  Returns the length from offset to the first line
2169  *                      containing only a dot (.) character.  A line
2170  *                      containing only a dot is used to indicate a
2171  *                      separation between multiple MGCP messages
2172  *                      piggybacked in the same UDP packet.
2173  *
2174  * Parameters:
2175  * tvb - The tvbuff in which we are looking for a dot line.
2176  * offset - The offset in tvb at which we will begin looking for
2177  *          a dot line.
2178  * len - The maximum distance from offset in tvb that we will look for
2179  *       a dot line.  If it is -1 we will look to the end of the buffer.
2180  *
2181  * next_offset - The location to write the offset of first character
2182  *               FOLLOWING the dot line.
2183  *
2184  * Returns: The length from offset to the first character BEFORE
2185  *          the dot line or -1 if the character at offset is a .
2186  *          followed by a newline or a carriage return.
2187  */
2188 static gint tvb_find_dot_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset)
2189 {
2190         gint tvb_current_offset, tvb_current_len, maxoffset,tvb_len;
2191         guint8 tempchar;
2192         tvb_current_offset = offset;
2193         tvb_current_len = len;
2194         tvb_len = tvb_length(tvb);
2195
2196         if (len == -1)
2197         {
2198                 maxoffset = tvb_len - 1;
2199         }
2200         else
2201         {
2202                 maxoffset = (len - 1) + offset;
2203         }
2204         tvb_current_offset = offset -1;
2205
2206         do
2207         {
2208                 tvb_current_offset = tvb_find_guint8(tvb, tvb_current_offset+1,
2209                                                      tvb_current_len, '.');
2210                 tvb_current_len = maxoffset - tvb_current_offset + 1;
2211
2212                 /* If we didn't find a . then break out of the loop */
2213                 if (tvb_current_offset == -1)
2214                 {
2215                         break;
2216                 }
2217
2218                 /* Do we have and characters following the . ? */
2219                 if (tvb_current_offset < maxoffset)
2220                 {
2221                         tempchar = tvb_get_guint8(tvb,tvb_current_offset+1);
2222                         /* Are the characters that follow the dot a newline or carriage return ? */
2223                         if (tempchar == '\r' || tempchar == '\n')
2224                         {
2225                                 /* Do we have any charaters that proceed the . ? */
2226                                 if (tvb_current_offset == 0)
2227                                 {
2228                                         break;
2229                                 }
2230                                 else
2231                                 {
2232                                         tempchar = tvb_get_guint8(tvb,tvb_current_offset-1);
2233
2234                                         /* Are the characters that follow the dot a newline or a
2235                                            carriage return ? */
2236                                         if (tempchar == '\r' || tempchar == '\n')
2237                                         {
2238                                                 break;
2239                                         }
2240                                 }
2241                         }
2242                 }
2243                 else
2244                 if (tvb_current_offset == maxoffset)
2245                 {
2246                         if (tvb_current_offset == 0)
2247                         {
2248                                 break;
2249                         }
2250                         else
2251                         {
2252                                 tempchar = tvb_get_guint8(tvb,tvb_current_offset-1);
2253                                 if (tempchar == '\r' || tempchar == '\n')
2254                                 {
2255                                         break;
2256                                 }
2257                         }
2258                 }
2259         } while (tvb_current_offset < maxoffset);
2260
2261
2262         /*
2263          * So now we either have the tvb_current_offset of a . in a dot line
2264          * or a tvb_current_offset of -1
2265          */
2266         if (tvb_current_offset == -1)
2267         {
2268                 tvb_current_offset = maxoffset +1;
2269                 *next_offset = maxoffset + 1;
2270         }
2271         else
2272         {
2273                 tvb_find_line_end(tvb,tvb_current_offset,tvb_current_len,next_offset,FALSE);
2274         }
2275
2276         if (tvb_current_offset == offset)
2277         {
2278                 tvb_current_len = -1;
2279         }
2280         else
2281         {
2282                 tvb_current_len = tvb_current_offset - offset;
2283         }
2284
2285         return tvb_current_len;
2286 }
2287