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