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