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