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