Preparations for dropping the old plugin api.
[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  *
11  * $Id$
12  *
13  * Copyright (c) 2000 by Ed Warnicke <hagbard@physics.rutgers.edu>
14  * Copyright (c) 2004 by Thomas Anders <thomas.anders [AT] blue-cable.de>
15  *
16  * Ethereal - Network traffic analyzer
17  * By Gerald Combs <gerald@ethereal.com>
18  * Copyright 1999 Gerald Combs
19  *
20  * This program is free software; you can redistribute it and/or
21  * modify it under the terms of the GNU General Public License
22  * as published by the Free Software Foundation; either version 2
23  * of the License, or (at your option) any later version.
24  *
25  * This program is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28  * GNU General Public License for more details.
29  *
30  * You should have received a copy of the GNU General Public License
31  * along with this program; if not, write to the Free Software
32  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
33  */
34
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38
39 #include "moduleinfo.h"
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <gmodule.h>
44 #include <ctype.h>
45 #include <time.h>
46 #include <string.h>
47 #include <epan/packet.h>
48 #include <epan/addr_resolv.h>
49 #include <epan/prefs.h>
50 #include <epan/strutil.h>
51 #include <epan/conversation.h>
52 #include <epan/tap.h>
53 #include "packet-mgcp.h"
54
55 #ifndef ENABLE_STATIC
56 G_MODULE_EXPORT const gchar version[] = VERSION;
57 #endif
58
59 #define TCP_PORT_MGCP_GATEWAY 2427
60 #define UDP_PORT_MGCP_GATEWAY 2427
61 #define TCP_PORT_MGCP_CALLAGENT 2727
62 #define UDP_PORT_MGCP_CALLAGENT 2727
63
64 void proto_reg_handoff_mgcp(void);
65
66
67 /* Define the mgcp proto */
68 static int proto_mgcp = -1;
69
70 /* Define many many headers for mgcp */
71 static int hf_mgcp_req = -1;
72 static int hf_mgcp_req_verb = -1;
73 static int hf_mgcp_req_endpoint = -1;
74 static int hf_mgcp_req_frame = -1;
75 static int hf_mgcp_rsp = -1;
76 static int hf_mgcp_rsp_frame = -1;
77 static int hf_mgcp_time = -1;
78 static int hf_mgcp_transid = -1;
79 static int hf_mgcp_version = -1;
80 static int hf_mgcp_rsp_rspcode = -1;
81 static int hf_mgcp_rsp_rspstring = -1;
82 static int hf_mgcp_param_rspack = -1;
83 static int hf_mgcp_param_bearerinfo = -1;
84 static int hf_mgcp_param_callid = -1;
85 static int hf_mgcp_param_connectionid = -1;
86 static int hf_mgcp_param_secondconnectionid = -1;
87 static int hf_mgcp_param_notifiedentity = -1;
88 static int hf_mgcp_param_requestid = -1;
89 static int hf_mgcp_param_localconnoptions = -1;
90 static int hf_mgcp_param_connectionmode = -1;
91 static int hf_mgcp_param_reqevents = -1;
92 static int hf_mgcp_param_restartmethod = -1;
93 static int hf_mgcp_param_restartdelay = -1;
94 static int hf_mgcp_param_signalreq  = -1;
95 static int hf_mgcp_param_digitmap = -1;
96 static int hf_mgcp_param_observedevent = -1;
97 static int hf_mgcp_param_connectionparam = -1;
98 static int hf_mgcp_param_connectionparam_ps = -1;
99 static int hf_mgcp_param_connectionparam_os = -1;
100 static int hf_mgcp_param_connectionparam_pr = -1;
101 static int hf_mgcp_param_connectionparam_or = -1;
102 static int hf_mgcp_param_connectionparam_pl = -1;
103 static int hf_mgcp_param_connectionparam_ji = -1;
104 static int hf_mgcp_param_connectionparam_la = -1;
105 static int hf_mgcp_param_connectionparam_pcrps = -1;
106 static int hf_mgcp_param_connectionparam_pcros = -1;
107 static int hf_mgcp_param_connectionparam_pcrpl = -1;
108 static int hf_mgcp_param_connectionparam_pcrji = -1;
109 static int hf_mgcp_param_connectionparam_x = -1;
110 static int hf_mgcp_param_reasoncode = -1;
111 static int hf_mgcp_param_eventstates = -1;
112 static int hf_mgcp_param_specificendpoint = -1;
113 static int hf_mgcp_param_secondendpointid = -1;
114 static int hf_mgcp_param_reqinfo = -1;
115 static int hf_mgcp_param_quarantinehandling = -1;
116 static int hf_mgcp_param_detectedevents = -1;
117 static int hf_mgcp_param_capabilities = -1;
118 static int hf_mgcp_param_extention = -1;
119 static int hf_mgcp_param_invalid = -1;
120 static int hf_mgcp_messagecount = -1;
121 static int hf_mgcp_dup = -1;
122 static int hf_mgcp_req_dup = -1;
123 static int hf_mgcp_rsp_dup = -1;
124
125 static const value_string mgcp_return_code_vals[] = {
126
127         {100, "The transaction is currently being executed.  An actual completion message will follow on later."},
128         {200, "The requested transaction was executed normally."},
129         {250, "The connection was deleted."},
130         {400, "The transaction could not be executed, due to a transient error."},
131         {401, "The phone is already off hook"},
132         {402, "The phone is already on hook"},
133         {403, "The transaction could not be executed, because the endpoint does not have sufficient resources at this time"},
134         {404, "Insufficient bandwidth at this time"},
135         {500, "The transaction could not be executed, because the endpoint is unknown."},
136         {501, "The transaction could not be executed, because the endpoint is not ready."},
137         {502, "The transaction could not be executed, because the endpoint does not have sufficient resources"},
138         {510, "The transaction could not be executed, because a protocol error was detected."},
139         {511, "The transaction could not be executed, because the command contained an unrecognized extension."},
140         {512, "The transaction could not be executed, because the gateway is not equipped to detect one of the requested events."},
141         {513, "The transaction could not be executed, because the gateway is not equipped to generate one of the requested signals."},
142         {514, "The transaction could not be executed, because the gateway cannot send the specified announcement."},
143         {515, "The transaction refers to an incorrect connection-id (may have been already deleted)"},
144         {516, "The transaction refers to an unknown call-id."},
145         {517, "Unsupported or invalid mode."},
146         {518, "Unsupported or unknown package."},
147         {519, "Endpoint does not have a digit map."},
148         {520, "The transaction could not be executed, because the endpoint is 'restarting'."},
149         {521, "Endpoint redirected to another Call Agent."},
150         {522, "No such event or signal."},
151         {523, "Unknown action or illegal combination of actions"},
152         {524, "Internal inconsistency in LocalConnectionOptions"},
153         {525, "Unknown extension in LocalConnectionOptions"},
154         {526, "Insufficient bandwidth"},
155         {527, "Missing RemoteConnectionDescriptor"},
156         {528, "Incompatible protocol version"},
157         {529, "Internal hardware failure"},
158         {530, "CAS signaling protocol error."},
159         {531, "failure of a grouping of trunks (e.g. facility failure)."},
160         {  0, NULL }
161 };
162
163 /*
164  * Define the trees for mgcp
165  * We need one for MGCP itself, one for the MGCP paramters and one
166  * for each of the dissected parameters
167  */
168 static int ett_mgcp = -1;
169 static int ett_mgcp_param = -1;
170 static int ett_mgcp_param_connectionparam = -1;
171
172 /*
173  * Define the tap for mgcp
174  */
175 static int mgcp_tap = -1;
176
177 /*
178  * Here are the global variables associated with
179  * the various user definable characteristics of the dissection
180  *
181  * MGCP has two kinds of "agents", gateways and callagents.  Callagents
182  * control gateways in a master/slave sort of arrangement.  Since gateways
183  * and callagents have different well known ports and could both
184  * operate under either udp or tcp we have rather a lot of port info to
185  * specify.
186  *
187  * global_mgcp_raw_text determines whether we are going to display
188  * the raw text of the mgcp message, much like the HTTP dissector does.
189  *
190  * global_mgcp_dissect_tree determines whether we are going to display
191  * a detailed tree that expresses a somewhat more semantically meaningful
192  * decode.
193  */
194 static int global_mgcp_gateway_tcp_port = TCP_PORT_MGCP_GATEWAY;
195 static int global_mgcp_gateway_udp_port = UDP_PORT_MGCP_GATEWAY;
196 static int global_mgcp_callagent_tcp_port = TCP_PORT_MGCP_CALLAGENT;
197 static int global_mgcp_callagent_udp_port = UDP_PORT_MGCP_CALLAGENT;
198 static gboolean global_mgcp_raw_text = FALSE;
199 static gboolean global_mgcp_dissect_tree = TRUE;
200 static gboolean global_mgcp_message_count = FALSE;
201
202 /*
203  * Variables to allow for proper deletion of dissector registration when
204  * the user changes port from the gui.
205  */
206 static int gateway_tcp_port = 0;
207 static int gateway_udp_port = 0;
208 static int callagent_tcp_port = 0;
209 static int callagent_udp_port = 0;
210
211 /* Some basic utility functions that are specific to this dissector */
212 static gboolean is_mgcp_verb(tvbuff_t *tvb, gint offset, gint maxlength);
213 static gboolean is_mgcp_rspcode(tvbuff_t *tvb, gint offset, gint maxlength);
214 static gint tvb_parse_param(tvbuff_t *tvb, gint offset, gint maxlength,
215                             int** hf);
216
217 /*
218  * The various functions that either dissect some
219  * subpart of MGCP.  These aren't really proto dissectors but they
220  * are written in the same style.
221  */
222 static void dissect_mgcp_message(tvbuff_t *tvb, packet_info *pinfo,
223                                  proto_tree *tree,proto_tree *mgcp_tree, proto_tree *ti);
224 static void dissect_mgcp_firstline(tvbuff_t *tvb, packet_info *pinfo,
225                                    proto_tree *tree);
226 static void dissect_mgcp_params(tvbuff_t *tvb,
227                                 proto_tree *tree);
228 static void dissect_mgcp_connectionparams(proto_tree *parent_tree, tvbuff_t *tvb, gint offset, gint param_type_len, gint param_val_len);
229 static void mgcp_raw_text_add(tvbuff_t *tvb,
230                               proto_tree *tree);
231
232 /*
233  * Some functions which should be moved to a library
234  * as I think that people may find them of general usefulness.
235  */
236 static gint tvb_skip_wsp(tvbuff_t* tvb, gint offset, gint maxlength);
237 static gint tvb_find_null_line(tvbuff_t* tvb, gint offset, gint len,
238                                gint* next_offset);
239 static gint tvb_find_dot_line(tvbuff_t* tvb, gint offset,
240                               gint len, gint* next_offset);
241 static gboolean is_rfc2234_alpha(guint8 c);
242
243 static dissector_handle_t sdp_handle;
244
245
246 /*
247  * Init Hash table stuff
248  */
249
250 typedef struct _mgcp_call_info_key {
251         guint32 transid;
252         conversation_t *conversation;
253 } mgcp_call_info_key;
254
255 static GMemChunk *mgcp_call_info_key_chunk;
256
257 static GMemChunk *mgcp_call_info_value_chunk;
258
259 static GHashTable *mgcp_calls;
260
261 /* compare 2 keys */
262 static gint
263 mgcp_call_equal(gconstpointer k1, gconstpointer k2)
264 {
265         const mgcp_call_info_key* key1 = (const mgcp_call_info_key*) k1;
266         const mgcp_call_info_key* key2 = (const mgcp_call_info_key*) k2;
267
268         return (key1->transid == key2->transid &&
269             key1->conversation == key2->conversation);
270 }
271
272
273 /* calculate a hash key */
274 static guint
275 mgcp_call_hash(gconstpointer k)
276 {
277         const mgcp_call_info_key* key = (const mgcp_call_info_key*) k;
278
279         return key->transid  + key->conversation->index;
280 }
281
282 /*
283  * dissect_mgcp - The dissector for the Media Gateway Control Protocol
284  */
285
286 static void
287 dissect_mgcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
288 {
289   gint sectionlen;
290   guint32 num_messages;
291   gint tvb_sectionend,tvb_sectionbegin, tvb_len, tvb_current_len;
292   proto_tree *mgcp_tree, *ti;
293
294   /* Initialize variables */
295   tvb_sectionend = 0;
296   tvb_sectionbegin = tvb_sectionend;
297   sectionlen = 0;
298   tvb_len = tvb_length(tvb);
299   tvb_current_len  = tvb_len;
300   num_messages = 0;
301   mgcp_tree = NULL;
302   ti = NULL;
303
304   /*
305    * Set the columns now, so that they'll be set correctly if we throw
306    * an exception.  We can set them later as well....
307    */
308   if (check_col(pinfo->cinfo, COL_PROTOCOL))
309     col_add_str(pinfo->cinfo, COL_PROTOCOL, "MGCP");
310   if (check_col(pinfo->cinfo, COL_INFO))
311     col_clear(pinfo->cinfo, COL_INFO);
312
313   /*
314    * Check to see whether we're really dealing with MGCP by looking
315    * for a valid MGCP verb or response code.  This isn't infallible,
316    * but its cheap and its better than nothing.
317    */
318   if(is_mgcp_verb(tvb,0,tvb_len) || is_mgcp_rspcode(tvb,0,tvb_len)){
319     /*
320      * Loop through however many mgcp messages may be stuck in
321      * this packet using piggybacking
322      */
323     do{
324       num_messages++;
325       if(tree){
326         /* Create our mgcp subtree */
327         ti = proto_tree_add_item(tree,proto_mgcp,tvb,0,0, FALSE);
328         mgcp_tree = proto_item_add_subtree(ti, ett_mgcp);
329       }
330
331       sectionlen = tvb_find_dot_line(tvb, tvb_sectionbegin, -1,
332                                      &tvb_sectionend);
333       if( sectionlen != -1){
334         dissect_mgcp_message(tvb_new_subset(tvb, tvb_sectionbegin,
335                                             sectionlen, -1),
336                              pinfo, tree, mgcp_tree,ti);
337         tvb_sectionbegin = tvb_sectionend;
338       }
339       else {
340         break;
341       }
342     } while(tvb_sectionend < tvb_len );
343     if(mgcp_tree){
344       proto_tree_add_uint_hidden(mgcp_tree, hf_mgcp_messagecount, tvb,
345                                  0 ,0 , num_messages);
346     }
347
348     /*
349      * Add our column information we do this after dissecting SDP
350      * in order to prevent the column info changing to reflect the SDP.
351      * XXX - can we do this with a fence?
352      */
353     tvb_sectionbegin = 0;
354     if (check_col(pinfo->cinfo, COL_PROTOCOL)){
355       if( global_mgcp_message_count == TRUE ){
356         if(num_messages > 1){
357           col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "MGCP (%i messages)",num_messages);
358         }
359         else {
360           col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "MGCP (%i message)",num_messages);
361         }
362       }
363       else {
364           col_add_str(pinfo->cinfo, COL_PROTOCOL, "MGCP");
365       }
366     }
367
368     if (check_col(pinfo->cinfo, COL_INFO) ){
369       sectionlen = tvb_find_line_end(tvb, tvb_sectionbegin,-1,
370                                      &tvb_sectionend,FALSE);
371       col_prepend_fstr(pinfo->cinfo, COL_INFO, "%s",
372                    tvb_format_text(tvb,tvb_sectionbegin,sectionlen));
373     }
374   }
375 }
376
377 static mgcp_info_t pi_arr[5]; /* We assuming a maximum of 5 mgcp messaages per packet */
378 static int pi_current=0;
379 static mgcp_info_t *mi;
380
381 static void
382 dissect_mgcp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
383                      proto_tree *mgcp_tree, proto_tree *ti){
384
385   /* Declare variables */
386   gint sectionlen;
387   gint tvb_sectionend,tvb_sectionbegin, tvb_len, tvb_current_len;
388   tvbuff_t *next_tvb;
389
390   /* Initialise stat info for passing to tap */
391   pi_current++;
392   if(pi_current==5){
393       pi_current=0;
394   }
395   mi=&pi_arr[pi_current];
396   
397   
398   mi->mgcp_type = MGCP_OTHERS;
399   mi->code[0] = '\0';
400   mi->transid = 0;
401   mi->req_time.secs=0;
402   mi->req_time.nsecs=0;
403   mi->is_duplicate = FALSE;
404   mi->request_available = FALSE;
405   mi->req_num = 0;
406   mi->endpointId = NULL;
407   mi->observedEvents = NULL;
408   mi->rspcode = 0;
409   mi->signalReq = NULL;
410   mi->hasDigitMap = FALSE;
411
412   /* Initialize variables */
413   tvb_sectionend = 0;
414   tvb_sectionbegin = tvb_sectionend;
415   sectionlen = 0;
416   tvb_len = tvb_length(tvb);
417   tvb_current_len  = tvb_len;
418
419   /*
420    * Check to see whether we're really dealing with MGCP by looking
421    * for a valid MGCP verb or response code.  This isn't infallible,
422    * but its cheap and its better than nothing.
423    */
424   if(is_mgcp_verb(tvb,0,tvb_len) || is_mgcp_rspcode(tvb,0,tvb_len)){
425     /* dissect first line */
426     tvb_sectionbegin = 0;
427     tvb_current_len = tvb_len;
428     tvb_sectionend = tvb_sectionbegin;
429     sectionlen = tvb_find_line_end(tvb,0,-1,&tvb_sectionend,FALSE);
430     if( sectionlen > 0){
431       dissect_mgcp_firstline(tvb_new_subset(tvb, tvb_sectionbegin,
432                                             sectionlen,-1), pinfo,
433                              mgcp_tree);
434     }
435     tvb_sectionbegin = tvb_sectionend;
436
437     /* dissect params */
438     if(tvb_sectionbegin < tvb_len){
439       sectionlen = tvb_find_null_line(tvb, tvb_sectionbegin, -1,
440                                       &tvb_sectionend);
441       dissect_mgcp_params(tvb_new_subset(tvb, tvb_sectionbegin,
442                                          sectionlen, -1),
443                           mgcp_tree);
444       tvb_sectionbegin = tvb_sectionend;
445     }
446
447     /* set the mgcp payload length correctly so we don't include the
448      * encapsulated SDP
449      */
450     sectionlen = tvb_sectionend;
451     proto_item_set_len(ti,sectionlen);
452
453     /* Display the raw text of the mgcp message if desired */
454
455     /* Do we want to display the raw text of our MGCP packet? */
456     if(global_mgcp_raw_text) {
457       if (tree)
458         mgcp_raw_text_add(tvb, mgcp_tree);
459     }
460
461     /* dissect sdp payload */
462     if( tvb_sectionend < tvb_len){
463       next_tvb = tvb_new_subset(tvb, tvb_sectionend, -1, -1);
464       call_dissector(sdp_handle, next_tvb, pinfo, tree);
465     }
466   }
467 }
468
469
470 /*
471  * Add the raw text of the message to the dissect tree if appropriate
472  * preferences are specified.
473  */
474
475 static void mgcp_raw_text_add(tvbuff_t *tvb, proto_tree *tree){
476
477   gint tvb_linebegin,tvb_lineend,tvb_len,linelen;
478
479   tvb_linebegin = 0;
480   tvb_len = tvb_length(tvb);
481
482   do {
483     tvb_find_line_end(tvb,tvb_linebegin,-1,&tvb_lineend,FALSE);
484     linelen = tvb_lineend - tvb_linebegin;
485     proto_tree_add_text(tree, tvb, tvb_linebegin, linelen,
486                         "%s", tvb_format_text(tvb,tvb_linebegin,
487                                               linelen));
488     tvb_linebegin = tvb_lineend;
489   } while ( tvb_lineend < tvb_len );
490 }
491
492 /* Discard and init any state we've saved */
493
494 static void
495 mgcp_init_protocol(void)
496 {
497         if (mgcp_calls != NULL) {
498                 g_hash_table_destroy(mgcp_calls);
499                 mgcp_calls = NULL;
500         }
501         if (mgcp_call_info_key_chunk != NULL) {
502                 g_mem_chunk_destroy(mgcp_call_info_key_chunk);
503                 mgcp_call_info_key_chunk = NULL;
504         }
505         if (mgcp_call_info_value_chunk != NULL) {
506                 g_mem_chunk_destroy(mgcp_call_info_value_chunk);
507                 mgcp_call_info_value_chunk = NULL;
508         }
509
510         mgcp_calls = g_hash_table_new(mgcp_call_hash, mgcp_call_equal);
511         mgcp_call_info_key_chunk = g_mem_chunk_new("call_info_key_chunk",
512             sizeof(mgcp_call_info_key),
513             200 * sizeof(mgcp_call_info_key),
514             G_ALLOC_ONLY);
515         mgcp_call_info_value_chunk = g_mem_chunk_new("call_info_value_chunk",
516             sizeof(mgcp_call_t),
517             200 * sizeof(mgcp_call_t),
518             G_ALLOC_ONLY);
519 }
520
521 /* Register all the bits needed with the filtering engine */
522
523 void
524 proto_register_mgcp(void)
525 {
526   static hf_register_info hf[] = {
527     { &hf_mgcp_req,
528       { "Request", "mgcp.req", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
529         "True if MGCP request", HFILL }},
530     { &hf_mgcp_rsp,
531       { "Response", "mgcp.rsp", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
532         "TRUE if MGCP response", HFILL }},
533     { &hf_mgcp_req_frame,
534       { "Request Frame", "mgcp.reqframe", FT_FRAMENUM, BASE_NONE, NULL, 0,
535         "Request Frame", HFILL }},
536     { &hf_mgcp_rsp_frame,
537       { "Response Frame", "mgcp.rspframe", FT_FRAMENUM, BASE_NONE, NULL, 0,
538         "Response Frame", HFILL }},
539     { &hf_mgcp_time,
540       { "Time from request", "mgcp.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0,
541         "Timedelta between Request and Response", HFILL }},
542     { &hf_mgcp_req_verb,
543       { "Verb", "mgcp.req.verb", FT_STRING, BASE_DEC, NULL, 0x0,
544         "Name of the verb", HFILL }},
545     { &hf_mgcp_req_endpoint,
546       { "Endpoint", "mgcp.req.endpoint", FT_STRING, BASE_DEC, NULL, 0x0,
547         "Endpoint referenced by the message", HFILL }},
548     { &hf_mgcp_transid,
549       { "Transaction ID", "mgcp.transid", FT_STRING, BASE_DEC, NULL, 0x0,
550         "Transaction ID of this message", HFILL }},
551     { &hf_mgcp_version,
552       { "Version", "mgcp.version", FT_STRING, BASE_DEC, NULL, 0x0,
553         "MGCP Version", HFILL }},
554     { &hf_mgcp_rsp_rspcode,
555       { "Response Code", "mgcp.rsp.rspcode", FT_UINT32, BASE_DEC, VALS(mgcp_return_code_vals), 0x0,
556         "Response Code", HFILL }},
557     { &hf_mgcp_rsp_rspstring,
558       { "Response String", "mgcp.rsp.rspstring", FT_STRING, BASE_DEC, NULL,
559         0x0, "Response String", HFILL }},
560     { &hf_mgcp_param_rspack,
561       { "ResponseAck (K)", "mgcp.param.rspack", FT_STRING, BASE_DEC, NULL,
562         0x0, "Response Ack", HFILL }},
563     { &hf_mgcp_param_bearerinfo,
564       { "BearerInformation (B)", "mgcp.param.bearerinfo", FT_STRING, BASE_DEC,
565         NULL, 0x0, "Bearer Information", HFILL }},
566     { &hf_mgcp_param_callid,
567       { "CallId (C)", "mgcp.param.callid", FT_STRING, BASE_DEC, NULL, 0x0,
568         "Call Id", HFILL }},
569     { &hf_mgcp_param_connectionid,
570       {"ConnectionIdentifier (I)", "mgcp.param.connectionid", FT_STRING,
571        BASE_DEC, NULL, 0x0, "Connection Identifier", HFILL }},
572     { &hf_mgcp_param_secondconnectionid,
573       { "SecondConnectionID (I2)", "mgcp.param.secondconnectionid", FT_STRING,
574        BASE_DEC, NULL, 0x0, "Second Connection Identifier", HFILL }},
575     { &hf_mgcp_param_notifiedentity,
576       { "NotifiedEntity (N)", "mgcp.param.notifiedentity", FT_STRING, BASE_DEC,
577         NULL, 0x0, "Notified Entity", HFILL }},
578     { &hf_mgcp_param_requestid,
579       { "RequestIdentifier (X)", "mgcp.param.requestid", FT_STRING, BASE_DEC,
580         NULL, 0x0, "Request Identifier", HFILL }},
581     { &hf_mgcp_param_localconnoptions,
582       { "LocalConnectionOptions (L)", "mgcp.param.localconnectionoptions",
583         FT_STRING, BASE_DEC, NULL, 0x0, "Local Connection Options", HFILL }},
584     { &hf_mgcp_param_connectionmode,
585       { "ConnectionMode (M)", "mgcp.param.connectionmode", FT_STRING, BASE_DEC,
586         NULL, 0x0, "Connection Mode", HFILL }},
587     { &hf_mgcp_param_reqevents,
588       { "RequestedEvents (R)", "mgcp.param.reqevents", FT_STRING, BASE_DEC,
589         NULL, 0x0, "Requested Events", HFILL }},
590     { &hf_mgcp_param_signalreq,
591       { "SignalRequests (S)", "mgcp.param.signalreq", FT_STRING, BASE_DEC,
592         NULL, 0x0, "Signal Request", HFILL }},
593     { &hf_mgcp_param_restartmethod,
594       { "RestartMethod (RM)", "mgcp.param.restartmethod", FT_STRING, BASE_DEC,
595         NULL, 0x0, "Restart Method", HFILL }},
596     { &hf_mgcp_param_restartdelay,
597       { "RestartDelay (RD)", "mgcp.param.restartdelay", FT_STRING, BASE_DEC,
598         NULL, 0x0, "Restart Delay", HFILL }},
599     { &hf_mgcp_param_digitmap,
600       { "DigitMap (D)", "mgcp.param.digitmap", FT_STRING, BASE_DEC, NULL, 0x0,
601         "Digit Map", HFILL }},
602     { &hf_mgcp_param_observedevent,
603       { "ObservedEvents (O)", "mgcp.param.observedevents", FT_STRING,
604         BASE_DEC, NULL, 0x0, "Observed Events", HFILL }},
605     { &hf_mgcp_param_connectionparam,
606       { "ConnectionParameters (P)", "mgcp.param.connectionparam", FT_STRING,
607         BASE_DEC, NULL, 0x0, "Connection Parameters", HFILL }},
608     { &hf_mgcp_param_connectionparam_ps,
609       { "Packets sent (PS)", "mgcp.param.connectionparam.ps", FT_UINT32,
610         BASE_DEC, NULL, 0x0, "Packets sent (P:PS)", HFILL }},
611     { &hf_mgcp_param_connectionparam_os,
612       { "Octets sent (OS)", "mgcp.param.connectionparam.os", FT_UINT32,
613         BASE_DEC, NULL, 0x0, "Octets sent (P:OS)", HFILL }},
614     { &hf_mgcp_param_connectionparam_pr,
615       { "Packets received (PR)", "mgcp.param.connectionparam.pr", FT_UINT32,
616         BASE_DEC, NULL, 0x0, "Packets received (P:PR)", HFILL }},
617     { &hf_mgcp_param_connectionparam_or,
618       { "Octets received (OR)", "mgcp.param.connectionparam.or", FT_UINT32,
619         BASE_DEC, NULL, 0x0, "Octets received (P:OR)", HFILL }},
620     { &hf_mgcp_param_connectionparam_pl,
621       { "Packets lost (PL)", "mgcp.param.connectionparam.pl", FT_UINT32,
622         BASE_DEC, NULL, 0x0, "Packets lost (P:PL)", HFILL }},
623     { &hf_mgcp_param_connectionparam_ji,
624       { "Jitter (JI)", "mgcp.param.connectionparam.ji", FT_UINT32,
625         BASE_DEC, NULL, 0x0, "Average inter-packet arrival jitter in milliseconds (P:JI)", HFILL }},
626     { &hf_mgcp_param_connectionparam_la,
627       { "Latency (LA)", "mgcp.param.connectionparam.la", FT_UINT32,
628         BASE_DEC, NULL, 0x0, "Average latency in milliseconds (P:LA)", HFILL }},
629     { &hf_mgcp_param_connectionparam_pcrps,
630       { "Remote Packets sent (PC/RPS)", "mgcp.param.connectionparam.pcrps", FT_UINT32,
631         BASE_DEC, NULL, 0x0, "Remote Packets sent (P:PC/RPS)", HFILL }},
632     { &hf_mgcp_param_connectionparam_pcros,
633       { "Remote Octets sent (PC/ROS)", "mgcp.param.connectionparam.pcros", FT_UINT32,
634         BASE_DEC, NULL, 0x0, "Remote Octets sent (P:PC/ROS)", HFILL }},
635     { &hf_mgcp_param_connectionparam_pcrpl,
636       { "Remote Packets lost (PC/RPL)", "mgcp.param.connectionparam.pcrpl", FT_UINT32,
637         BASE_DEC, NULL, 0x0, "Remote Packets lost (P:PC/RPL)", HFILL }},
638     { &hf_mgcp_param_connectionparam_pcrji,
639       { "Remote Jitter (PC/RJI)", "mgcp.param.connectionparam.pcrji", FT_UINT32,
640         BASE_DEC, NULL, 0x0, "Remote Jitter (P:PC/RJI)", HFILL }},
641     { &hf_mgcp_param_connectionparam_x,
642       { "Vendor Extension", "mgcp.param.connectionparam.x", FT_STRING,
643         BASE_DEC, NULL, 0x0, "Vendor Extension (P:X-*)", HFILL }},
644     { &hf_mgcp_param_reasoncode,
645       { "ReasonCode (E)", "mgcp.param.reasoncode", FT_STRING, BASE_DEC,
646         NULL, 0x0, "Reason Code", HFILL }},
647     { &hf_mgcp_param_eventstates,
648       { "EventStates (ES)", "mgcp.param.eventstates", FT_STRING, BASE_DEC,
649         NULL, 0x0, "Event States", HFILL }},
650     { &hf_mgcp_param_specificendpoint,
651       { "SpecificEndpointID (Z)", "mgcp.param.specificendpointid", FT_STRING,
652         BASE_DEC, NULL, 0x0, "Specific Endpoint ID", HFILL }},
653     { &hf_mgcp_param_secondendpointid,
654       { "SecondEndpointID (Z2)", "mgcp.param.secondendpointid", FT_STRING,
655         BASE_DEC, NULL, 0x0, "Second Endpoing ID", HFILL }},
656     { &hf_mgcp_param_reqinfo,
657       { "RequestedInfo (F)", "mgcp.param.reqinfo", FT_STRING, BASE_DEC,
658         NULL, 0x0,"Requested Info", HFILL }},
659     { &hf_mgcp_param_quarantinehandling,
660       { "QuarantineHandling (Q)", "mgcp.param.quarantinehandling", FT_STRING,
661         BASE_DEC, NULL, 0x0, "Quarantine Handling", HFILL }},
662     { &hf_mgcp_param_detectedevents,
663       { "DetectedEvents (T)", "mgcp.param.detectedevents", FT_STRING, BASE_DEC,
664         NULL, 0x0, "Detected Events", HFILL }},
665     { &hf_mgcp_param_capabilities,
666       { "Capabilities (A)", "mgcp.param.capabilities", FT_STRING, BASE_DEC,
667         NULL, 0x0, "Capabilities", HFILL }},
668     { &hf_mgcp_param_extention,
669       { "Extention Parameter (X-*)", "mgcp.param.extention", FT_STRING,
670         BASE_DEC, NULL, 0x0, "Extension Parameter", HFILL }},
671     { &hf_mgcp_param_invalid,
672       { "Invalid Parameter", "mgcp.param.invalid", FT_STRING,
673         BASE_DEC, NULL, 0x0, "Invalid Parameter", HFILL }},
674     { &hf_mgcp_messagecount,
675       { "MGCP Message Count", "mgcp.messagecount", FT_UINT32,
676         BASE_DEC, NULL, 0x0, "Number of MGCP message in a packet", HFILL }},
677     { &hf_mgcp_dup,
678       { "Duplicate Message", "mgcp.dup", FT_UINT32, BASE_DEC,
679         NULL, 0, "Duplicate Message", HFILL }},
680     { &hf_mgcp_req_dup,
681       { "Duplicate Request", "mgcp.req.dup", FT_UINT32, BASE_DEC,
682         NULL, 0, "Duplicate Request", HFILL }},
683     { &hf_mgcp_rsp_dup,
684       { "Duplicate Response", "mgcp.rsp.dup", FT_UINT32, BASE_DEC,
685         NULL, 0, "Duplicate Response", HFILL }},
686     /* Add more fields here */
687   };
688   static gint *ett[] = {
689     &ett_mgcp,
690     &ett_mgcp_param,
691     &ett_mgcp_param_connectionparam,
692   };
693   module_t *mgcp_module;
694
695   proto_mgcp = proto_register_protocol("Media Gateway Control Protocol",
696                                        "MGCP", "mgcp");
697
698   proto_register_field_array(proto_mgcp, hf, array_length(hf));
699   proto_register_subtree_array(ett, array_length(ett));
700   register_init_routine(&mgcp_init_protocol);
701
702   /* Register our configuration options for , particularly our ports */
703
704   mgcp_module = prefs_register_protocol(proto_mgcp, proto_reg_handoff_mgcp);
705
706   prefs_register_uint_preference(mgcp_module, "tcp.gateway_port",
707                                  "MGCP Gateway TCP Port",
708                                  "Set the UDP port for gateway messages "
709                                  "(if other than the default of 2427)",
710                                  10, &global_mgcp_gateway_tcp_port);
711
712   prefs_register_uint_preference(mgcp_module, "udp.gateway_port",
713                                  "MGCP Gateway UDP Port",
714                                  "Set the TCP port for gateway messages "
715                                  "(if other than the default of 2427)",
716                                  10, &global_mgcp_gateway_udp_port);
717
718   prefs_register_uint_preference(mgcp_module, "tcp.callagent_port",
719                                  "MGCP Callagent TCP Port",
720                                  "Set the TCP port for callagent messages "
721                                  "(if other than the default of 2727)",
722                                  10, &global_mgcp_callagent_tcp_port);
723
724   prefs_register_uint_preference(mgcp_module, "udp.callagent_port",
725                                  "MGCP Callagent UDP Port",
726                                  "Set the UDP port for callagent messages "
727                                  "(if other than the default of 2727)",
728                                  10, &global_mgcp_callagent_udp_port);
729
730
731   prefs_register_bool_preference(mgcp_module, "display_raw_text",
732                                  "Display raw text for MGCP message",
733                                  "Specifies that the raw text of the "
734                                  "MGCP message should be displayed "
735                                  "instead of (or in addition to) the "
736                                  "dissection tree",
737                                  &global_mgcp_raw_text);
738
739   prefs_register_bool_preference(mgcp_module, "display_dissect_tree",
740                                  "Display tree dissection for MGCP message",
741                                  "Specifies that the dissection tree of the "
742                                  "MGCP message should be displayed "
743                                  "instead of (or in addition to) the "
744                                  "raw text",
745                                  &global_mgcp_dissect_tree);
746
747   prefs_register_bool_preference(mgcp_module, "display_mgcp_message_count",
748                                  "Display the number of MGCP messages",
749                                  "Display the number of MGCP messages "
750                                  "found in a packet in the protocol column.",
751                                  &global_mgcp_message_count);
752
753   mgcp_tap = register_tap("mgcp");
754 }
755
756 /* The registration hand-off routine */
757 void
758 proto_reg_handoff_mgcp(void)
759 {
760   static int mgcp_prefs_initialized = FALSE;
761   static dissector_handle_t mgcp_handle;
762
763   /*
764    * Get a handle for the SDP dissector.
765    */
766   sdp_handle = find_dissector("sdp");
767
768   if (!mgcp_prefs_initialized) {
769     mgcp_handle = create_dissector_handle(dissect_mgcp, proto_mgcp);
770     mgcp_prefs_initialized = TRUE;
771   }
772   else {
773     dissector_delete("tcp.port", gateway_tcp_port, mgcp_handle);
774     dissector_delete("udp.port", gateway_udp_port, mgcp_handle);
775     dissector_delete("tcp.port", callagent_tcp_port, mgcp_handle);
776     dissector_delete("udp.port", callagent_udp_port, mgcp_handle);
777   }
778
779   /* Set our port number for future use */
780
781   gateway_tcp_port = global_mgcp_gateway_tcp_port;
782   gateway_udp_port = global_mgcp_gateway_udp_port;
783
784   callagent_tcp_port = global_mgcp_callagent_tcp_port;
785   callagent_udp_port = global_mgcp_callagent_udp_port;
786
787   dissector_add("tcp.port", global_mgcp_gateway_tcp_port, mgcp_handle);
788   dissector_add("udp.port", global_mgcp_gateway_udp_port, mgcp_handle);
789   dissector_add("tcp.port", global_mgcp_callagent_tcp_port, mgcp_handle);
790   dissector_add("udp.port", global_mgcp_callagent_udp_port, mgcp_handle);
791
792 }
793
794 /*
795  * is_mgcp_verb - A function for determining whether there is a
796  *                MGCP verb at offset in tvb
797  *
798  * Parameter:
799  * tvb - The tvbuff in which we are looking for an MGCP verb
800  * offset - The offset in tvb at which we are looking for a MGCP verb
801  * maxlength - The maximum distance from offset we may look for the
802  *             characters that make up a MGCP verb.
803  *
804  * Return: TRUE if there is an MGCP verb at offset in tvb, otherwise FALSE
805  */
806
807 static gboolean is_mgcp_verb(tvbuff_t *tvb, gint offset, gint maxlength){
808   int returnvalue = FALSE;
809   guint8 word[5];
810
811   if(( maxlength >= 4) && tvb_get_nstringz0(tvb,offset,sizeof(word),word)){
812     if (strncasecmp(word, "EPCF", 4) == 0 ||
813         strncasecmp(word, "CRCX", 4) == 0 ||
814         strncasecmp(word, "MDCX", 4) == 0 ||
815         strncasecmp(word, "DLCX", 4) == 0 ||
816         strncasecmp(word, "RQNT", 4) == 0 ||
817         strncasecmp(word, "NTFY", 4) == 0 ||
818         strncasecmp(word, "AUEP", 4) == 0 ||
819         strncasecmp(word, "AUCX", 4) == 0 ||
820         strncasecmp(word, "RSIP", 4) == 0 ||
821         (word[0] == 'X' && is_rfc2234_alpha(word[1]) && is_rfc2234_alpha(word[2]) &&
822          is_rfc2234_alpha(word[3]))
823         ){
824       returnvalue = TRUE;
825     }
826   }
827   if( returnvalue && maxlength >= 5 &&
828       (word[0] = tvb_get_guint8(tvb,4)) != ' ' && word[0] != '\t'){
829     returnvalue = FALSE;
830   }
831   return returnvalue;
832 }
833
834 /*
835  * is_mgcp_rspcode - A function for determining whether something which
836  *                   looks roughly like a MGCP response code is at
837  *                   offset in tvb
838  *
839  * Parameters:
840  * tvb - The tvbuff in which we are looking for an MGCP response code
841  * offset - The offset in tvb at which we are looking for a MGCP response code
842  * maxlength - The maximum distance from offset we may look for the
843  *             characters that make up a MGCP response code.
844  *
845  * Return: TRUE if there is an MGCP response code at offset in tvb,
846  *         otherwise FALSE
847  */
848
849 static gboolean is_mgcp_rspcode(tvbuff_t *tvb, gint offset, gint maxlength){
850   int returnvalue = FALSE;
851   guint8 word[4];
852   if(maxlength >= 3){
853     tvb_get_nstringz0(tvb,offset,sizeof(word),word);
854     if( isdigit(word[0]) &&
855         isdigit(word[1]) &&
856         isdigit(word[2])){
857       returnvalue = TRUE;
858     }
859   }
860   if( returnvalue && maxlength >= 4 &&
861       (word[0] = tvb_get_guint8(tvb,3)) != ' ' && word[0] != '\t'){
862     returnvalue = FALSE;
863   }
864   return returnvalue;
865 }
866
867 /*
868  * is_rfc2234_alpha - Indicates whether the character c is an alphabetical
869  *                    character.  This function is used instead of
870  *                    isalpha because isalpha may deviate from the rfc2234
871  *                    definition of ALPHA in some locales.
872  *
873  * Parameter:
874  * c - The character being checked for being an alphabetical character.
875  *
876  * Return: TRUE if c is an upper or lower case alphabetical character,
877  *         FALSE otherwise.
878  */
879
880 static gboolean is_rfc2234_alpha(guint8 c){
881   int returnvalue = FALSE;
882   if(( c <= 'Z' && c >= 'A' ) || (c <= 'z' && c >= 'a')){
883     returnvalue = TRUE;
884   }
885   return returnvalue;
886 }
887
888 /*
889  * tvb_parse_param - Parse the MGCP param into a type and a value.
890  *
891  * Parameters:
892  * tvb - The tvbuff containing the MGCP param we are to parse.
893  * offset - The offset in tvb at which we will begin looking for a
894  *          MGCP parameter to parse.
895  * len - The maximum distance from offset in tvb that we can look for
896  *       an MGCP parameter to parse.
897  * hf - The place to write a pointer to the integer representing the
898  *      header field associated with the MGCP parameter parsed.
899  *
900  * Returns: The offset in tvb where the value of the MGCP parameter
901  *          begins.
902  */
903 static gint tvb_parse_param(tvbuff_t* tvb, gint offset, gint len, int** hf){
904   gint returnvalue, tvb_current_offset,counter;
905   guint8 tempchar;
906   gchar **buf;
907   tvb_current_offset = offset;
908   returnvalue = -1;  
909   buf = NULL;
910   *hf = NULL;
911   if(len > 0){
912     tempchar = tvb_get_guint8(tvb,tvb_current_offset);
913     switch(tempchar){
914     case 'K':
915       *hf = &hf_mgcp_param_rspack;
916       break;
917     case 'B':
918       *hf = &hf_mgcp_param_bearerinfo;
919       break;
920     case 'C':
921       *hf = &hf_mgcp_param_callid;
922       break;
923     case 'I':
924       tvb_current_offset++;
925       if(len > (tvb_current_offset - offset) &&
926          (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':'){
927         *hf = &hf_mgcp_param_connectionid;
928         tvb_current_offset--;
929       }
930       else if ( tempchar == '2'){
931         *hf = &hf_mgcp_param_secondconnectionid;
932       }
933       break;
934     case 'N':
935       *hf = &hf_mgcp_param_notifiedentity;
936       break;
937     case 'X':
938       tvb_current_offset++;
939       if(len > (tvb_current_offset - offset) &&
940          (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':'){
941         *hf = &hf_mgcp_param_requestid;
942       }
943       else if(len > (tvb_current_offset - offset) && (
944          (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == '-' ||
945          tempchar == '+')){
946         tvb_current_offset++;
947         for(counter = 1;(counter <= 6) && (len > (counter + tvb_current_offset
948                                                   - offset))
949               && ( is_rfc2234_alpha(tempchar =
950                                     tvb_get_guint8(tvb,
951                                                    tvb_current_offset+counter))
952                    || isdigit(tempchar));counter++);
953         if(tempchar == ':'){
954           tvb_current_offset += counter;
955           *hf = &hf_mgcp_param_extention;
956         }
957       }
958       tvb_current_offset--;
959       break;
960     case 'L':
961       *hf = &hf_mgcp_param_localconnoptions;
962       break;
963     case 'M':
964       *hf = &hf_mgcp_param_connectionmode;
965       break;
966     case 'R':
967       tvb_current_offset++;
968       if(len > (tvb_current_offset - offset) &&
969          (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':'){
970         *hf = &hf_mgcp_param_reqevents;
971         tvb_current_offset--;
972       }
973       else if ( tempchar == 'M'){
974         *hf = &hf_mgcp_param_restartmethod;
975       }
976       else if ( tempchar == 'D'){
977         *hf = &hf_mgcp_param_restartdelay;
978       }
979       break;
980     case 'S':
981       *hf = &hf_mgcp_param_signalreq;
982           buf = &(mi->signalReq);
983       break;
984     case 'D':
985       *hf = &hf_mgcp_param_digitmap;
986           mi->hasDigitMap = TRUE;
987       break;
988     case 'O':
989       *hf = &hf_mgcp_param_observedevent;
990           buf = &(mi->observedEvents);
991       break;
992     case 'P':
993       *hf = &hf_mgcp_param_connectionparam;
994       break;
995     case 'E':
996       tvb_current_offset++;
997       if(len > (tvb_current_offset - offset) &&
998          (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':'){
999         *hf = &hf_mgcp_param_reasoncode;
1000         tvb_current_offset--;
1001       }
1002       else if ( tempchar == 'S'){
1003         *hf = &hf_mgcp_param_eventstates;
1004       }
1005       break;
1006     case 'Z':
1007       tvb_current_offset++;
1008       if(len > (tvb_current_offset - offset) &&
1009          (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':'){
1010         *hf = &hf_mgcp_param_specificendpoint;
1011         tvb_current_offset--;
1012       }
1013       else if ( tempchar == '2'){
1014         *hf = &hf_mgcp_param_secondendpointid;
1015       }
1016       break;
1017     case 'F':
1018       *hf = &hf_mgcp_param_reqinfo;
1019       break;
1020
1021     case 'Q':
1022       *hf = &hf_mgcp_param_quarantinehandling;
1023       break;
1024
1025     case 'T':
1026       *hf = &hf_mgcp_param_detectedevents;
1027       break;
1028
1029     case 'A':
1030       *hf = &hf_mgcp_param_capabilities;
1031       break;
1032     default:
1033       *hf = &hf_mgcp_param_invalid;
1034       break;
1035     }
1036
1037     tvb_current_offset++;
1038     if(*hf != NULL && len > (tvb_current_offset - offset) &&
1039        (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':'){
1040       tvb_current_offset++;
1041       tvb_current_offset = tvb_skip_wsp(tvb,tvb_current_offset,
1042                                         (len - tvb_current_offset + offset));
1043       returnvalue = tvb_current_offset;
1044           if (buf != NULL) {
1045                   *buf = tvb_get_string(tvb, tvb_current_offset, (len - tvb_current_offset + offset));
1046           }
1047     }
1048     else {
1049       *hf = &hf_mgcp_param_invalid;
1050     }
1051   }
1052   else{
1053     *hf = &hf_mgcp_param_invalid;
1054   }
1055   if(*hf == &hf_mgcp_param_invalid){
1056     returnvalue = offset;
1057   }
1058   return returnvalue;
1059 }
1060
1061
1062 /*
1063  * dissect_mgcp_firstline - Dissects the firstline of an MGCP message.
1064  *                          Adds the appropriate headers fields to
1065  *                          tree for the dissection of the first line
1066  *                          of an MGCP message.
1067  *
1068  * Parameters:
1069  * tvb - The tvb containing the first line of an MGCP message.  This
1070  *       tvb is presumed to ONLY contain the first line of the MGCP
1071  *       message.
1072  * pinfo - The packet info for the packet.  This is not really used
1073  *         by this function but is passed through so as to retain the
1074  *         style of a dissector.
1075  * tree - The tree from which to hang the structured information parsed
1076  *        from the first line of the MGCP message.
1077  */
1078
1079  
1080
1081 static void dissect_mgcp_firstline(tvbuff_t *tvb, packet_info *pinfo,
1082                                    proto_tree *tree){
1083   gint tvb_current_offset,tvb_previous_offset,tvb_len,tvb_current_len;
1084   gint tokennum, tokenlen;
1085   char *transid = NULL;
1086   char *code = NULL;
1087   char *endpointId = NULL;
1088   mgcp_type_t mgcp_type = MGCP_OTHERS;
1089   conversation_t* conversation;
1090   mgcp_call_info_key mgcp_call_key;
1091   mgcp_call_info_key *new_mgcp_call_key = NULL;
1092   mgcp_call_t *mgcp_call = NULL;
1093   nstime_t delta;
1094   gint rspcode = 0;
1095
1096   static address null_address = { AT_NONE, 0, NULL };
1097   proto_item* (*my_proto_tree_add_string)(proto_tree*, int, tvbuff_t*, gint,
1098                                           gint, const char*);
1099   tvb_previous_offset = 0;
1100   tvb_len = tvb_length(tvb);
1101   tvb_current_len = tvb_len;
1102   tvb_current_offset = tvb_previous_offset;
1103   mi->is_duplicate = FALSE;
1104   mi->request_available = FALSE;
1105
1106   if(tree){
1107     tokennum = 0;
1108
1109     if(global_mgcp_dissect_tree){
1110       my_proto_tree_add_string = proto_tree_add_string;
1111     }
1112     else{
1113       my_proto_tree_add_string = proto_tree_add_string_hidden;
1114     }
1115
1116     do {
1117       tvb_current_len = tvb_length_remaining(tvb,tvb_previous_offset);
1118       tvb_current_offset = tvb_find_guint8(tvb, tvb_previous_offset,
1119                                            tvb_current_len, ' ');
1120       if(tvb_current_offset == -1){
1121         tvb_current_offset = tvb_len;
1122         tokenlen = tvb_current_len;
1123       }
1124       else{
1125         tokenlen = tvb_current_offset - tvb_previous_offset;
1126       }
1127       if(tokennum == 0){
1128         code = tvb_format_text(tvb,tvb_previous_offset,tokenlen);
1129         strncpy(mi->code,code,4);
1130         mi->code[4] = '\0';
1131         if(is_mgcp_verb(tvb,tvb_previous_offset,tvb_current_len)){
1132           mgcp_type = MGCP_REQUEST;
1133           my_proto_tree_add_string(tree,hf_mgcp_req_verb, tvb,
1134                                    tvb_previous_offset, tokenlen,
1135                                    code);
1136         }
1137         else if (is_mgcp_rspcode(tvb,tvb_previous_offset,tvb_current_len)){
1138           mgcp_type = MGCP_RESPONSE;
1139           rspcode = atoi(code);
1140           mi->rspcode = rspcode;
1141           proto_tree_add_uint(tree,hf_mgcp_rsp_rspcode, tvb,
1142                                    tvb_previous_offset, tokenlen,
1143                                    rspcode);
1144
1145         }
1146         else {
1147           break;
1148         }
1149       }
1150       if(tokennum == 1){
1151         transid = tvb_format_text(tvb,tvb_previous_offset,tokenlen);
1152         /* XXX - what if this isn't a valid text string? */
1153         mi->transid = atol(transid);
1154         my_proto_tree_add_string(tree,hf_mgcp_transid, tvb,
1155                                  tvb_previous_offset, tokenlen,
1156                                  transid);
1157       }
1158       if(tokennum == 2){
1159         if(mgcp_type == MGCP_REQUEST){
1160           endpointId = tvb_format_text(tvb, tvb_previous_offset,tokenlen);
1161           mi->endpointId = g_strdup(endpointId);
1162           my_proto_tree_add_string(tree,hf_mgcp_req_endpoint, tvb,
1163                                    tvb_previous_offset, tokenlen,
1164                                    endpointId);
1165         }
1166         else if(mgcp_type == MGCP_RESPONSE){
1167           if(tvb_current_offset < tvb_len){
1168             tokenlen = tvb_find_line_end(tvb, tvb_previous_offset,
1169                                          -1,&tvb_current_offset,FALSE);
1170           }
1171           else{
1172             tokenlen = tvb_current_len;
1173           }
1174           my_proto_tree_add_string(tree, hf_mgcp_rsp_rspstring, tvb,
1175                                    tvb_previous_offset, tokenlen,
1176                                    tvb_format_text(tvb, tvb_previous_offset,
1177                                                    tokenlen));
1178           break;
1179         }
1180       }
1181       if( (tokennum == 3 && mgcp_type == MGCP_REQUEST) ){
1182         if(tvb_current_offset < tvb_len ){
1183           tokenlen = tvb_find_line_end(tvb, tvb_previous_offset,
1184                                        -1,&tvb_current_offset,FALSE);
1185         }
1186         else{
1187           tokenlen = tvb_current_len;
1188         }
1189         my_proto_tree_add_string(tree,hf_mgcp_version, tvb,
1190                                  tvb_previous_offset, tokenlen,
1191                                  tvb_format_text(tvb,tvb_previous_offset,
1192                                                  tokenlen));
1193         break;
1194       }
1195       if(tvb_current_offset < tvb_len){
1196         tvb_previous_offset = tvb_skip_wsp(tvb, tvb_current_offset,
1197                                            tvb_current_len);
1198       }
1199       tokennum++;
1200     } while( tvb_current_offset < tvb_len && tvb_previous_offset < tvb_len
1201              && tokennum <= 3);
1202
1203     switch (mgcp_type){
1204     case MGCP_RESPONSE:
1205         proto_tree_add_boolean_hidden(tree, hf_mgcp_rsp, tvb, 0, 0, TRUE);
1206         /* Check for MGCP response.  A response must match a call that
1207            we've seen, and the response must be sent to the same
1208            port and address that the call came from, and must
1209            come from the port to which the call was sent.
1210
1211            If the transport is connection-oriented (we check, for
1212            now, only for "pinfo->ptype" of PT_TCP), we take
1213            into account the address from which the call was sent
1214            and the address to which the call was sent, because
1215            the addresses of the two endpoints should be the same
1216            for all calls and replies.
1217
1218            If the transport is connectionless, we don't worry
1219            about the address to which the call was sent and from
1220            which the reply was sent, because there's no
1221            guarantee that the reply will come from the address
1222            to which the call was sent. */
1223         if (pinfo->ptype == PT_TCP) {
1224                 conversation = find_conversation(pinfo->fd->num, &pinfo->src,
1225                     &pinfo->dst, pinfo->ptype, pinfo->srcport,
1226                     pinfo->destport, 0);
1227         } else {
1228                 /*
1229                  * XXX - can we just use NO_ADDR_B?  Unfortunately,
1230                  * you currently still have to pass a non-null
1231                  * pointer for the second address argument even
1232                  * if you do that.
1233                  */
1234                 conversation = find_conversation(pinfo->fd->num, &null_address,
1235                     &pinfo->dst, pinfo->ptype, pinfo->srcport,
1236                     pinfo->destport, 0);
1237         }
1238         if (conversation != NULL) {
1239                 /* look only for matching request, if
1240                    matching conversation is available. */
1241                 mgcp_call_key.transid = mi->transid;
1242                 mgcp_call_key.conversation = conversation;
1243                 mgcp_call = g_hash_table_lookup(mgcp_calls, &mgcp_call_key);
1244                 if(mgcp_call) {
1245                         /* Indicate the frame to which this is a reply. */
1246                         if(mgcp_call->req_num){
1247                                 mi->request_available = TRUE;
1248                                 mgcp_call->responded = TRUE;
1249                                 mi->req_num = mgcp_call->req_num;
1250                                 strcpy(mi->code,mgcp_call->code);
1251                                 proto_tree_add_uint_format(tree, hf_mgcp_req_frame,
1252                                     tvb, 0, 0, mgcp_call->req_num,
1253                                     "This is a response to a request in frame %u",
1254                                     mgcp_call->req_num);
1255                                 delta.secs= pinfo->fd->abs_secs-mgcp_call->req_time.secs;
1256                                 delta.nsecs=pinfo->fd->abs_usecs*1000-mgcp_call->req_time.nsecs;
1257                                 if(delta.nsecs<0){
1258                                         delta.nsecs+=1000000000;
1259                                         delta.secs--;
1260                                 }
1261                                 proto_tree_add_time(tree, hf_mgcp_time, tvb, 0, 0,
1262                                         &delta);
1263                         }
1264
1265                         if (mgcp_call->rsp_num == 0) {
1266                                 /* We have not yet seen a response to that call, so
1267                                    this must be the first response; remember its
1268                                    frame number. */
1269                                 mgcp_call->rsp_num = pinfo->fd->num;
1270                         } else {
1271                                 /* We have seen a response to this call - but was it
1272                                    *this* response? */
1273                                 if (mgcp_call->rsp_num != pinfo->fd->num) {
1274                                         /* No, so it's a duplicate response.
1275                                            Mark it as such. */
1276                                         mi->is_duplicate = TRUE;
1277                                         if (check_col(pinfo->cinfo, COL_INFO)) {
1278                                                 col_append_fstr(pinfo->cinfo, COL_INFO,
1279                                                         ", Duplicate Response %u",mi->transid);
1280                                                 if (tree) {
1281                                                         proto_tree_add_uint_hidden(tree,
1282                                                                 hf_mgcp_dup, tvb, 0,0, mi->transid);
1283                                                         proto_tree_add_uint_hidden(tree,
1284                                                                 hf_mgcp_rsp_dup, tvb, 0,0, mi->transid);
1285                                                 }
1286                                         }
1287                                 }
1288                         }
1289                 }
1290         }
1291       break;
1292     case MGCP_REQUEST:
1293         proto_tree_add_boolean_hidden(tree, hf_mgcp_req, tvb, 0, 0, TRUE);
1294         /* Keep track of the address and port whence the call came,
1295            and the port to which the call is being sent, so that
1296            we can match up calls with replies.
1297
1298            If the transport is connection-oriented (we check, for
1299            now, only for "pinfo->ptype" of PT_TCP), we take
1300            into account the address from which the call was sent
1301            and the address to which the call was sent, because
1302            the addresses of the two endpoints should be the same
1303            for all calls and replies.
1304
1305            If the transport is connectionless, we don't worry
1306            about the address to which the call was sent and from
1307            which the reply was sent, because there's no
1308            guarantee that the reply will come from the address
1309            to which the call was sent. */
1310         if (pinfo->ptype == PT_TCP) {
1311                 conversation = find_conversation(pinfo->fd->num, &pinfo->src,
1312                     &pinfo->dst, pinfo->ptype, pinfo->srcport,
1313                     pinfo->destport, 0);
1314         } else {
1315                 /*
1316                  * XXX - can we just use NO_ADDR_B?  Unfortunately,
1317                  * you currently still have to pass a non-null
1318                  * pointer for the second address argument even
1319                  * if you do that.
1320                  */
1321                 conversation = find_conversation(pinfo->fd->num, &pinfo->src,
1322                     &null_address, pinfo->ptype, pinfo->srcport,
1323                     pinfo->destport, 0);
1324         }
1325         if (conversation == NULL) {
1326                 /* It's not part of any conversation - create a new
1327                    one. */
1328                 if (pinfo->ptype == PT_TCP) {
1329                         conversation = conversation_new(pinfo->fd->num, &pinfo->src,
1330                             &pinfo->dst, pinfo->ptype, pinfo->srcport,
1331                             pinfo->destport, 0);
1332                 } else {
1333                         conversation = conversation_new(pinfo->fd->num, &pinfo->src,
1334                             &null_address, pinfo->ptype, pinfo->srcport,
1335                             pinfo->destport, 0);
1336                 }
1337         }
1338
1339         /* prepare the key data */
1340         mgcp_call_key.transid = mi->transid;
1341         mgcp_call_key.conversation = conversation;
1342
1343         /* look up the request */
1344         mgcp_call = g_hash_table_lookup(mgcp_calls, &mgcp_call_key);
1345         if (mgcp_call != NULL) {
1346                 /* We've seen a request with this TRANSID, with the same
1347                    source and destination, before - but was it
1348                    *this* request? */
1349                 if (pinfo->fd->num != mgcp_call->req_num) {
1350                         /* No, so it's a duplicate request.
1351                            Mark it as such. */
1352                         mi->is_duplicate = TRUE;
1353                         mi->req_num = mgcp_call->req_num;
1354                         if (check_col(pinfo->cinfo, COL_INFO)) {
1355                                 col_append_fstr(pinfo->cinfo, COL_INFO,
1356                                         ", Duplicate Request %u",mi->transid);
1357                                 if (tree) {
1358                                         proto_tree_add_uint_hidden(tree,
1359                                                 hf_mgcp_dup, tvb, 0,0, mi->transid);
1360                                         proto_tree_add_uint_hidden(tree,
1361                                                 hf_mgcp_req_dup, tvb, 0,0, mi->transid);
1362                                 }
1363                         }
1364                 }
1365         }
1366         else {
1367                 /* Prepare the value data.
1368                    "req_num" and "rsp_num" are frame numbers;
1369                    frame numbers are 1-origin, so we use 0
1370                    to mean "we don't yet know in which frame
1371                    the reply for this call appears". */
1372                 new_mgcp_call_key = g_mem_chunk_alloc(mgcp_call_info_key_chunk);
1373                 *new_mgcp_call_key = mgcp_call_key;
1374                 mgcp_call = g_mem_chunk_alloc(mgcp_call_info_value_chunk);
1375                 mgcp_call->req_num = pinfo->fd->num;
1376                 mgcp_call->rsp_num = 0;
1377                 mgcp_call->transid = mi->transid;
1378                 mgcp_call->responded = FALSE;
1379                 mgcp_call->req_time.secs=pinfo->fd->abs_secs;
1380                 mgcp_call->req_time.nsecs=pinfo->fd->abs_usecs*1000;
1381                 strcpy(mgcp_call->code,mi->code);
1382                 /* store it */
1383                 g_hash_table_insert(mgcp_calls, new_mgcp_call_key, mgcp_call);
1384         }
1385         if(mgcp_call && mgcp_call->rsp_num){
1386                 proto_tree_add_uint_format(tree, hf_mgcp_rsp_frame,
1387                     tvb, 0, 0, mgcp_call->rsp_num,
1388                     "The response to this request is in frame %u",
1389                     mgcp_call->rsp_num);
1390         }
1391       break;
1392     default:
1393       break;
1394     }
1395     mi->mgcp_type = mgcp_type;
1396     if(mgcp_call) {
1397         mi->req_time.secs=mgcp_call->req_time.secs;
1398         mi->req_time.nsecs=mgcp_call->req_time.nsecs;
1399     }
1400   }
1401   tap_queue_packet(mgcp_tap, pinfo, mi);
1402 }
1403
1404 /*
1405  * dissect_mgcp_params - Dissects the parameters of an MGCP message.
1406  *                       Adds the appropriate headers fields to
1407  *                       tree for the dissection of the parameters
1408  *                       of an MGCP message.
1409  *
1410  * Parameters:
1411  * tvb - The tvb containing the parameters of an MGCP message.  This
1412  *       tvb is presumed to ONLY contain the part of the MGCP
1413  *       message which contains the MGCP parameters.
1414  * tree - The tree from which to hang the structured information parsed
1415  *        from the parameters of the MGCP message.
1416  */
1417 static void dissect_mgcp_params(tvbuff_t *tvb, proto_tree *tree){
1418   int linelen, tokenlen, *my_param;
1419   gint tvb_lineend,tvb_current_len, tvb_linebegin,tvb_len;
1420   gint tvb_tokenbegin;
1421   proto_tree *mgcp_param_ti, *mgcp_param_tree;
1422   proto_item* (*my_proto_tree_add_string)(proto_tree*, int, tvbuff_t*, gint,
1423                                           gint, const char*);
1424
1425   tvb_len = tvb_length(tvb);
1426   tvb_linebegin = 0;
1427   tvb_current_len = tvb_length_remaining(tvb,tvb_linebegin);
1428   tvb_lineend = tvb_linebegin;
1429
1430   if(tree){
1431     if(global_mgcp_dissect_tree){
1432       my_proto_tree_add_string = proto_tree_add_string;
1433       mgcp_param_ti = proto_tree_add_item(tree, proto_mgcp, tvb,
1434                                           tvb_linebegin, tvb_len, FALSE);
1435       proto_item_set_text(mgcp_param_ti, "Parameters");
1436       mgcp_param_tree = proto_item_add_subtree(mgcp_param_ti, ett_mgcp_param);
1437     }
1438     else{
1439       my_proto_tree_add_string = proto_tree_add_string_hidden;
1440       mgcp_param_tree = tree;
1441       mgcp_param_ti = NULL;
1442     }
1443
1444     /* Parse the parameters */
1445     while(tvb_lineend < tvb_len){
1446       linelen = tvb_find_line_end(tvb, tvb_linebegin, -1,&tvb_lineend,FALSE);
1447       tvb_tokenbegin = tvb_parse_param(tvb, tvb_linebegin, linelen,
1448                                        &my_param);
1449
1450       if (*my_param == hf_mgcp_param_connectionparam) {
1451         tokenlen = tvb_find_line_end(tvb,tvb_tokenbegin,-1,&tvb_lineend,FALSE);
1452         dissect_mgcp_connectionparams(mgcp_param_tree, tvb, tvb_linebegin, tvb_tokenbegin - tvb_linebegin, tokenlen);
1453       } else {
1454         tokenlen = tvb_find_line_end(tvb,tvb_tokenbegin,-1,&tvb_lineend,FALSE);
1455         my_proto_tree_add_string(mgcp_param_tree,*my_param, tvb,
1456                                  tvb_linebegin, linelen,
1457                                  tvb_format_text(tvb,tvb_tokenbegin,
1458                                                  tokenlen));
1459       }
1460       tvb_linebegin = tvb_lineend;
1461     }
1462   }
1463 }
1464
1465 static void
1466 dissect_mgcp_connectionparams(proto_tree *parent_tree, tvbuff_t *tvb, gint offset, gint param_type_len, gint param_val_len)
1467 {
1468   proto_tree *tree = parent_tree;
1469   proto_item *item = NULL;
1470   proto_item* (*my_proto_tree_add_uint)(proto_tree*, int, tvbuff_t*, gint, gint, guint32) = NULL;
1471   proto_item* (*my_proto_tree_add_string)(proto_tree*, int, tvbuff_t*, gint, gint, const char*) = NULL;
1472   proto_item* (*my_proto_tree_add_text)(proto_tree*, tvbuff_t*, gint, gint, const char *, ...) = NULL;
1473
1474   gchar *tokenline = NULL;
1475   gchar **tokens = NULL;
1476   gchar **typval = NULL;
1477   guint i = 0;
1478   guint tokenlen = 0;
1479   int hf_uint = -1;
1480   int hf_string = -1;
1481
1482   if (parent_tree) {
1483     if (global_mgcp_dissect_tree){
1484       my_proto_tree_add_uint = proto_tree_add_uint;
1485       my_proto_tree_add_string = proto_tree_add_string;
1486       my_proto_tree_add_text = proto_tree_add_text;
1487       item = proto_tree_add_item(parent_tree, hf_mgcp_param_connectionparam, tvb, offset, param_type_len+param_val_len, FALSE);
1488       tree = proto_item_add_subtree(item, ett_mgcp_param_connectionparam);
1489     } else {
1490       my_proto_tree_add_uint = proto_tree_add_uint_hidden;
1491       my_proto_tree_add_string = proto_tree_add_string_hidden;
1492       my_proto_tree_add_text = NULL;
1493     }
1494   }
1495   /* the P: line */
1496   offset += param_type_len; /* skip the P: */
1497   tokenline = tvb_get_string(tvb, offset, param_val_len);
1498   /* split into type=value pairs separated by comma */
1499   tokens = g_strsplit(tokenline, ",", -1);
1500   for (i = 0; tokens[i] != NULL; i++) {
1501     tokenlen = strlen(tokens[i]);
1502     typval = g_strsplit(tokens[i], "=", 2);
1503     if ((typval[0] != NULL) && (typval[1] != NULL)) {
1504       if (!strcasecmp(g_strstrip(typval[0]), "PS")) {
1505         hf_uint = hf_mgcp_param_connectionparam_ps;
1506       } else if (!strcasecmp(g_strstrip(typval[0]), "OS")) {
1507         hf_uint = hf_mgcp_param_connectionparam_os;
1508       } else if (!strcasecmp(g_strstrip(typval[0]), "PR")) {
1509         hf_uint = hf_mgcp_param_connectionparam_pr;
1510       } else if (!strcasecmp(g_strstrip(typval[0]), "OR")) {
1511         hf_uint = hf_mgcp_param_connectionparam_or;
1512       } else if (!strcasecmp(g_strstrip(typval[0]), "PL")) {
1513         hf_uint = hf_mgcp_param_connectionparam_pl;
1514       } else if (!strcasecmp(g_strstrip(typval[0]), "JI")) {
1515         hf_uint = hf_mgcp_param_connectionparam_ji;
1516       } else if (!strcasecmp(g_strstrip(typval[0]), "LA")) {
1517         hf_uint = hf_mgcp_param_connectionparam_la;
1518       } else if (!strcasecmp(g_strstrip(typval[0]), "PC/RPS")) {
1519         hf_uint = hf_mgcp_param_connectionparam_pcrps;
1520       } else if (!strcasecmp(g_strstrip(typval[0]), "PC/ROS")) {
1521         hf_uint = hf_mgcp_param_connectionparam_pcros;
1522       } else if (!strcasecmp(g_strstrip(typval[0]), "PC/RPL")) {
1523         hf_uint = hf_mgcp_param_connectionparam_pcrpl;
1524       } else if (!strcasecmp(g_strstrip(typval[0]), "PC/RJI")) {
1525         hf_uint = hf_mgcp_param_connectionparam_pcrji;
1526       } else if (!strncasecmp(g_strstrip(typval[0]), "X-", 2)) {
1527         hf_string = hf_mgcp_param_connectionparam_x;
1528       } else {
1529         hf_uint = -1;
1530         hf_string = -1;
1531       }
1532       if (hf_uint != -1) {
1533         if (my_proto_tree_add_uint) my_proto_tree_add_uint(tree, hf_uint, tvb, offset, tokenlen, atol(typval[1]));
1534       } else if (hf_string != -1) {
1535         if (my_proto_tree_add_string) my_proto_tree_add_string(tree, hf_string, tvb, offset, tokenlen, g_strstrip(typval[1]));
1536       } else {
1537         if (my_proto_tree_add_text) proto_tree_add_text(tree, tvb, offset, tokenlen, "Unknown parameter: %s", tokens[i]);
1538       }
1539     } else {
1540       if (my_proto_tree_add_text) proto_tree_add_text(tree, tvb, offset, tokenlen, "Malformed parameter: %s", tokens[i]);
1541     }
1542     offset += tokenlen+1; /* 1 extra for the delimiter */
1543   }
1544   g_strfreev(typval);
1545   g_strfreev(tokens);
1546   g_free(tokenline);
1547 }
1548
1549 /*
1550  * tvb_skip_wsp - Returns the position in tvb of the first non-whitespace
1551  *                character following offset or offset + maxlength -1 whichever
1552  *                is smaller.
1553  *
1554  * Parameters:
1555  * tvb - The tvbuff in which we are skipping whitespace.
1556  * offset - The offset in tvb from which we begin trying to skip whitespace.
1557  * maxlength - The maximum distance from offset that we may try to skip
1558  * whitespace.
1559  *
1560  * Returns: The position in tvb of the first non-whitespace
1561  *          character following offset or offset + maxlength -1 whichever
1562  *          is smaller.
1563  */
1564 static gint tvb_skip_wsp(tvbuff_t* tvb, gint offset, gint maxlength){
1565   gint counter = offset;
1566   gint end = offset + maxlength,tvb_len;
1567   guint8 tempchar;
1568   tvb_len = tvb_length(tvb);
1569   end = offset + maxlength;
1570   if(end >= tvb_len){
1571     end = tvb_len;
1572   }
1573   for(counter = offset; counter < end &&
1574         ((tempchar = tvb_get_guint8(tvb,counter)) == ' ' ||
1575         tempchar == '\t');counter++);
1576   return (counter);
1577 }
1578
1579 /*
1580  * tvb_find_null_line - Returns the length from offset to the first null
1581  *                      line found (a null line is a line that begins
1582  *                      with a CR or LF.  The offset to the first character
1583  *                      after the null line is written into the gint pointed
1584  *                      to by next_offset.
1585  *
1586  * Parameters:
1587  * tvb - The tvbuff in which we are looking for a null line.
1588  * offset - The offset in tvb at which we will begin looking for
1589  *          a null line.
1590  * len - The maximum distance from offset in tvb that we will look for
1591  *       a null line.  If it is -1 we will look to the end of the buffer.
1592  *
1593  * next_offset - The location to write the offset of first character
1594  *               FOLLOWING the null line.
1595  *
1596  * Returns: The length from offset to the first character BEFORE
1597  *          the null line..
1598  */
1599 static gint tvb_find_null_line(tvbuff_t* tvb, gint offset,
1600                                gint len, gint* next_offset){
1601   gint tvb_lineend,tvb_current_len,tvb_linebegin,maxoffset;
1602   guint tempchar;
1603
1604   tvb_linebegin = offset;
1605   tvb_lineend = tvb_linebegin;
1606
1607   /* Simple setup to allow for the traditional -1 search to the end
1608    * of the tvbuff
1609    */
1610   if(len != -1){
1611     tvb_current_len = len;
1612   }
1613   else{
1614     tvb_current_len = tvb_length_remaining(tvb,offset);
1615   }
1616   maxoffset = (tvb_current_len - 1) + offset;
1617
1618   /*
1619    * Loop around until we either find a line begining with a carriage return
1620    * or newline character or until we hit the end of the tvbuff.
1621    */
1622   do {
1623     tvb_linebegin = tvb_lineend;
1624     tvb_current_len = tvb_length_remaining(tvb,tvb_linebegin);
1625     tvb_find_line_end(tvb, tvb_linebegin, tvb_current_len, &tvb_lineend,FALSE);
1626     tempchar = tvb_get_guint8(tvb,tvb_linebegin);
1627   }
1628   while( tempchar != '\r' && tempchar != '\n' &&
1629          tvb_lineend <= maxoffset);
1630
1631   *next_offset = tvb_lineend;
1632
1633   if( tvb_lineend <= maxoffset ) {
1634     tvb_current_len = tvb_linebegin - offset;
1635   }
1636   else {
1637     tvb_current_len = tvb_length_remaining(tvb,offset);
1638   }
1639
1640   return (tvb_current_len);
1641 }
1642
1643 /*
1644  * tvb_find_dot_line -  Returns the length from offset to the first line
1645  *                      containing only a dot (.) character.  A line
1646  *                      containing only a dot is used to indicate a
1647  *                      separation between multiple MGCP messages
1648  *                      piggybacked in the same UDP packet.
1649  *
1650  * Parameters:
1651  * tvb - The tvbuff in which we are looking for a dot line.
1652  * offset - The offset in tvb at which we will begin looking for
1653  *          a dot line.
1654  * len - The maximum distance from offset in tvb that we will look for
1655  *       a dot line.  If it is -1 we will look to the end of the buffer.
1656  *
1657  * next_offset - The location to write the offset of first character
1658  *               FOLLOWING the dot line.
1659  *
1660  * Returns: The length from offset to the first character BEFORE
1661  *          the dot line or -1 if the character at offset is a .
1662  *          followed by a newline or a carriage return.
1663  */
1664 static gint tvb_find_dot_line(tvbuff_t* tvb, gint offset,
1665                                gint len, gint* next_offset){
1666   gint tvb_current_offset, tvb_current_len, maxoffset,tvb_len;
1667   guint8 tempchar;
1668
1669   tvb_current_offset = offset;
1670   tvb_current_len = len;
1671   tvb_len = tvb_length(tvb);
1672
1673   if(len == -1){
1674     maxoffset = ( tvb_len - 1 );
1675   }
1676   else {
1677     maxoffset = (len - 1 ) + offset;
1678   }
1679   tvb_current_offset = offset -1;
1680   do {
1681     tvb_current_offset = tvb_find_guint8(tvb, tvb_current_offset+1,
1682                                          tvb_current_len, '.');
1683     tvb_current_len = maxoffset - tvb_current_offset + 1;
1684     /*
1685      * if we didn't find a . then break out of the loop
1686      */
1687     if(tvb_current_offset == -1){
1688       break;
1689     }
1690     /* do we have and characters following the . ? */
1691     if( tvb_current_offset < maxoffset ) {
1692       tempchar = tvb_get_guint8(tvb,tvb_current_offset+1);
1693       /*
1694        * are the characters that follow the dot a newline or carriage return ?
1695        */
1696       if(tempchar == '\r' || tempchar == '\n'){
1697         /*
1698          * do we have any charaters that proceed the . ?
1699          */
1700         if( tvb_current_offset == 0 ){
1701           break;
1702         }
1703         else {
1704           tempchar = tvb_get_guint8(tvb,tvb_current_offset-1);
1705           /*
1706            * are the characters that follow the dot a newline or a carriage
1707            * return ?
1708            */
1709           if(tempchar == '\r' || tempchar == '\n'){
1710             break;
1711           }
1712         }
1713       }
1714     }
1715     else if ( tvb_current_offset == maxoffset ) {
1716       if( tvb_current_offset == 0 ){
1717         break;
1718       }
1719       else {
1720         tempchar = tvb_get_guint8(tvb,tvb_current_offset-1);
1721         if(tempchar == '\r' || tempchar == '\n'){
1722           break;
1723         }
1724       }
1725     }
1726   } while (tvb_current_offset < maxoffset);
1727   /*
1728    * so now we either have the tvb_current_offset of a . in a dot line
1729    * or a tvb_current_offset of -1
1730    */
1731   if(tvb_current_offset == -1){
1732     tvb_current_offset = maxoffset +1;
1733     *next_offset = maxoffset + 1;
1734   }
1735   else {
1736     tvb_find_line_end(tvb,tvb_current_offset,tvb_current_len,next_offset,FALSE);
1737   }
1738
1739   if( tvb_current_offset == offset ){
1740     tvb_current_len = -1;
1741   }
1742   else {
1743     tvb_current_len = tvb_current_offset - offset;
1744   }
1745   return tvb_current_len;
1746 }
1747
1748 /* Start the functions we need for the plugin stuff */
1749
1750 #ifndef ENABLE_STATIC
1751
1752 G_MODULE_EXPORT void
1753 plugin_reg_handoff(void){
1754   proto_reg_handoff_mgcp();
1755 }
1756
1757 G_MODULE_EXPORT void
1758 new_plugin_init(void)
1759 {
1760   /* register the new protocol, protocol fields, and subtrees */
1761   if (proto_mgcp == -1) { /* execute protocol initialization only once */
1762     proto_register_mgcp();
1763   }
1764 }
1765
1766 #endif
1767
1768 /* End the functions we need for plugin stuff */