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