2 * Routines for mgcp packet disassembly
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/
13 * Copyright (c) 2000 by Ed Warnicke <hagbard@physics.rutgers.edu>
14 * Copyright (c) 2004 by Thomas Anders <thomas.anders [AT] blue-cable.de>
16 * Ethereal - Network traffic analyzer
17 * By Gerald Combs <gerald@ethereal.com>
18 * Copyright 1999 Gerald Combs
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.
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.
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.
39 #include "moduleinfo.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>
53 #include "packet-mgcp.h"
56 G_MODULE_EXPORT const gchar version[] = VERSION;
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
64 void proto_reg_handoff_mgcp(void);
67 /* Define the mgcp proto */
68 static int proto_mgcp = -1;
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;
125 static const value_string mgcp_return_code_vals[] = {
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)."},
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
168 static int ett_mgcp = -1;
169 static int ett_mgcp_param = -1;
170 static int ett_mgcp_param_connectionparam = -1;
173 * Define the tap for mgcp
175 static int mgcp_tap = -1;
178 * Here are the global variables associated with
179 * the various user definable characteristics of the dissection
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
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.
190 * global_mgcp_dissect_tree determines whether we are going to display
191 * a detailed tree that expresses a somewhat more semantically meaningful
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;
203 * Variables to allow for proper deletion of dissector registration when
204 * the user changes port from the gui.
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;
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,
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.
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,
226 static void dissect_mgcp_params(tvbuff_t *tvb,
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,
233 * Some functions which should be moved to a library
234 * as I think that people may find them of general usefulness.
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,
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);
243 static dissector_handle_t sdp_handle;
247 * Init Hash table stuff
250 typedef struct _mgcp_call_info_key {
252 conversation_t *conversation;
253 } mgcp_call_info_key;
255 static GMemChunk *mgcp_call_info_key_chunk;
257 static GMemChunk *mgcp_call_info_value_chunk;
259 static GHashTable *mgcp_calls;
263 mgcp_call_equal(gconstpointer k1, gconstpointer k2)
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;
268 return (key1->transid == key2->transid &&
269 key1->conversation == key2->conversation);
273 /* calculate a hash key */
275 mgcp_call_hash(gconstpointer k)
277 const mgcp_call_info_key* key = (const mgcp_call_info_key*) k;
279 return key->transid + key->conversation->index;
283 * dissect_mgcp - The dissector for the Media Gateway Control Protocol
287 dissect_mgcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
290 guint32 num_messages;
291 gint tvb_sectionend,tvb_sectionbegin, tvb_len, tvb_current_len;
292 proto_tree *mgcp_tree, *ti;
294 /* Initialize variables */
296 tvb_sectionbegin = tvb_sectionend;
298 tvb_len = tvb_length(tvb);
299 tvb_current_len = tvb_len;
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....
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);
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.
318 if(is_mgcp_verb(tvb,0,tvb_len) || is_mgcp_rspcode(tvb,0,tvb_len)){
320 * Loop through however many mgcp messages may be stuck in
321 * this packet using piggybacking
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);
331 sectionlen = tvb_find_dot_line(tvb, tvb_sectionbegin, -1,
333 if( sectionlen != -1){
334 dissect_mgcp_message(tvb_new_subset(tvb, tvb_sectionbegin,
336 pinfo, tree, mgcp_tree,ti);
337 tvb_sectionbegin = tvb_sectionend;
342 } while(tvb_sectionend < tvb_len );
344 proto_tree_add_uint_hidden(mgcp_tree, hf_mgcp_messagecount, tvb,
345 0 ,0 , num_messages);
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?
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);
360 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "MGCP (%i message)",num_messages);
364 col_add_str(pinfo->cinfo, COL_PROTOCOL, "MGCP");
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));
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;
382 dissect_mgcp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
383 proto_tree *mgcp_tree, proto_tree *ti){
385 /* Declare variables */
387 gint tvb_sectionend,tvb_sectionbegin, tvb_len, tvb_current_len;
390 /* Initialise stat info for passing to tap */
395 mi=&pi_arr[pi_current];
398 mi->mgcp_type = MGCP_OTHERS;
402 mi->req_time.nsecs=0;
403 mi->is_duplicate = FALSE;
404 mi->request_available = FALSE;
406 mi->endpointId = NULL;
407 mi->observedEvents = NULL;
409 mi->signalReq = NULL;
410 mi->hasDigitMap = FALSE;
412 /* Initialize variables */
414 tvb_sectionbegin = tvb_sectionend;
416 tvb_len = tvb_length(tvb);
417 tvb_current_len = tvb_len;
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.
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);
431 dissect_mgcp_firstline(tvb_new_subset(tvb, tvb_sectionbegin,
432 sectionlen,-1), pinfo,
435 tvb_sectionbegin = tvb_sectionend;
438 if(tvb_sectionbegin < tvb_len){
439 sectionlen = tvb_find_null_line(tvb, tvb_sectionbegin, -1,
441 dissect_mgcp_params(tvb_new_subset(tvb, tvb_sectionbegin,
444 tvb_sectionbegin = tvb_sectionend;
447 /* set the mgcp payload length correctly so we don't include the
450 sectionlen = tvb_sectionend;
451 proto_item_set_len(ti,sectionlen);
453 /* Display the raw text of the mgcp message if desired */
455 /* Do we want to display the raw text of our MGCP packet? */
456 if(global_mgcp_raw_text) {
458 mgcp_raw_text_add(tvb, mgcp_tree);
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);
471 * Add the raw text of the message to the dissect tree if appropriate
472 * preferences are specified.
475 static void mgcp_raw_text_add(tvbuff_t *tvb, proto_tree *tree){
477 gint tvb_linebegin,tvb_lineend,tvb_len,linelen;
480 tvb_len = tvb_length(tvb);
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,
488 tvb_linebegin = tvb_lineend;
489 } while ( tvb_lineend < tvb_len );
492 /* Discard and init any state we've saved */
495 mgcp_init_protocol(void)
497 if (mgcp_calls != NULL) {
498 g_hash_table_destroy(mgcp_calls);
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;
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;
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),
515 mgcp_call_info_value_chunk = g_mem_chunk_new("call_info_value_chunk",
517 200 * sizeof(mgcp_call_t),
521 /* Register all the bits needed with the filtering engine */
524 proto_register_mgcp(void)
526 static hf_register_info hf[] = {
528 { "Request", "mgcp.req", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
529 "True if MGCP request", HFILL }},
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 }},
540 { "Time from request", "mgcp.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0,
541 "Timedelta between Request and Response", HFILL }},
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 }},
549 { "Transaction ID", "mgcp.transid", FT_STRING, BASE_DEC, NULL, 0x0,
550 "Transaction ID of this message", HFILL }},
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,
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 }},
678 { "Duplicate Message", "mgcp.dup", FT_UINT32, BASE_DEC,
679 NULL, 0, "Duplicate Message", HFILL }},
681 { "Duplicate Request", "mgcp.req.dup", FT_UINT32, BASE_DEC,
682 NULL, 0, "Duplicate Request", HFILL }},
684 { "Duplicate Response", "mgcp.rsp.dup", FT_UINT32, BASE_DEC,
685 NULL, 0, "Duplicate Response", HFILL }},
686 /* Add more fields here */
688 static gint *ett[] = {
691 &ett_mgcp_param_connectionparam,
693 module_t *mgcp_module;
695 proto_mgcp = proto_register_protocol("Media Gateway Control Protocol",
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);
702 /* Register our configuration options for , particularly our ports */
704 mgcp_module = prefs_register_protocol(proto_mgcp, proto_reg_handoff_mgcp);
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);
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);
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);
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);
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 "
737 &global_mgcp_raw_text);
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 "
745 &global_mgcp_dissect_tree);
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);
753 mgcp_tap = register_tap("mgcp");
756 /* The registration hand-off routine */
758 proto_reg_handoff_mgcp(void)
760 static int mgcp_prefs_initialized = FALSE;
761 static dissector_handle_t mgcp_handle;
764 * Get a handle for the SDP dissector.
766 sdp_handle = find_dissector("sdp");
768 if (!mgcp_prefs_initialized) {
769 mgcp_handle = create_dissector_handle(dissect_mgcp, proto_mgcp);
770 mgcp_prefs_initialized = TRUE;
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);
779 /* Set our port number for future use */
781 gateway_tcp_port = global_mgcp_gateway_tcp_port;
782 gateway_udp_port = global_mgcp_gateway_udp_port;
784 callagent_tcp_port = global_mgcp_callagent_tcp_port;
785 callagent_udp_port = global_mgcp_callagent_udp_port;
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);
795 * is_mgcp_verb - A function for determining whether there is a
796 * MGCP verb at offset in tvb
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.
804 * Return: TRUE if there is an MGCP verb at offset in tvb, otherwise FALSE
807 static gboolean is_mgcp_verb(tvbuff_t *tvb, gint offset, gint maxlength){
808 int returnvalue = FALSE;
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]))
827 if( returnvalue && maxlength >= 5 &&
828 (word[0] = tvb_get_guint8(tvb,4)) != ' ' && word[0] != '\t'){
835 * is_mgcp_rspcode - A function for determining whether something which
836 * looks roughly like a MGCP response code is at
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.
845 * Return: TRUE if there is an MGCP response code at offset in tvb,
849 static gboolean is_mgcp_rspcode(tvbuff_t *tvb, gint offset, gint maxlength){
850 int returnvalue = FALSE;
853 tvb_get_nstringz0(tvb,offset,sizeof(word),word);
854 if( isdigit(word[0]) &&
860 if( returnvalue && maxlength >= 4 &&
861 (word[0] = tvb_get_guint8(tvb,3)) != ' ' && word[0] != '\t'){
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.
874 * c - The character being checked for being an alphabetical character.
876 * Return: TRUE if c is an upper or lower case alphabetical character,
880 static gboolean is_rfc2234_alpha(guint8 c){
881 int returnvalue = FALSE;
882 if(( c <= 'Z' && c >= 'A' ) || (c <= 'z' && c >= 'a')){
889 * tvb_parse_param - Parse the MGCP param into a type and a value.
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.
900 * Returns: The offset in tvb where the value of the MGCP parameter
903 static gint tvb_parse_param(tvbuff_t* tvb, gint offset, gint len, int** hf){
904 gint returnvalue, tvb_current_offset,counter;
907 tvb_current_offset = offset;
912 tempchar = tvb_get_guint8(tvb,tvb_current_offset);
915 *hf = &hf_mgcp_param_rspack;
918 *hf = &hf_mgcp_param_bearerinfo;
921 *hf = &hf_mgcp_param_callid;
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--;
930 else if ( tempchar == '2'){
931 *hf = &hf_mgcp_param_secondconnectionid;
935 *hf = &hf_mgcp_param_notifiedentity;
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;
943 else if(len > (tvb_current_offset - offset) && (
944 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == '-' ||
946 tvb_current_offset++;
947 for(counter = 1;(counter <= 6) && (len > (counter + tvb_current_offset
949 && ( is_rfc2234_alpha(tempchar =
951 tvb_current_offset+counter))
952 || isdigit(tempchar));counter++);
954 tvb_current_offset += counter;
955 *hf = &hf_mgcp_param_extention;
958 tvb_current_offset--;
961 *hf = &hf_mgcp_param_localconnoptions;
964 *hf = &hf_mgcp_param_connectionmode;
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--;
973 else if ( tempchar == 'M'){
974 *hf = &hf_mgcp_param_restartmethod;
976 else if ( tempchar == 'D'){
977 *hf = &hf_mgcp_param_restartdelay;
981 *hf = &hf_mgcp_param_signalreq;
982 buf = &(mi->signalReq);
985 *hf = &hf_mgcp_param_digitmap;
986 mi->hasDigitMap = TRUE;
989 *hf = &hf_mgcp_param_observedevent;
990 buf = &(mi->observedEvents);
993 *hf = &hf_mgcp_param_connectionparam;
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--;
1002 else if ( tempchar == 'S'){
1003 *hf = &hf_mgcp_param_eventstates;
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--;
1013 else if ( tempchar == '2'){
1014 *hf = &hf_mgcp_param_secondendpointid;
1018 *hf = &hf_mgcp_param_reqinfo;
1022 *hf = &hf_mgcp_param_quarantinehandling;
1026 *hf = &hf_mgcp_param_detectedevents;
1030 *hf = &hf_mgcp_param_capabilities;
1033 *hf = &hf_mgcp_param_invalid;
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;
1045 *buf = tvb_get_string(tvb, tvb_current_offset, (len - tvb_current_offset + offset));
1049 *hf = &hf_mgcp_param_invalid;
1053 *hf = &hf_mgcp_param_invalid;
1055 if(*hf == &hf_mgcp_param_invalid){
1056 returnvalue = offset;
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.
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
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.
1081 static void dissect_mgcp_firstline(tvbuff_t *tvb, packet_info *pinfo,
1083 gint tvb_current_offset,tvb_previous_offset,tvb_len,tvb_current_len;
1084 gint tokennum, tokenlen;
1085 char *transid = 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;
1096 static address null_address = { AT_NONE, 0, NULL };
1097 proto_item* (*my_proto_tree_add_string)(proto_tree*, int, tvbuff_t*, gint,
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;
1109 if(global_mgcp_dissect_tree){
1110 my_proto_tree_add_string = proto_tree_add_string;
1113 my_proto_tree_add_string = proto_tree_add_string_hidden;
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;
1125 tokenlen = tvb_current_offset - tvb_previous_offset;
1128 code = tvb_format_text(tvb,tvb_previous_offset,tokenlen);
1129 strncpy(mi->code,code,4);
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,
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,
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,
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,
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);
1172 tokenlen = tvb_current_len;
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,
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);
1187 tokenlen = tvb_current_len;
1189 my_proto_tree_add_string(tree,hf_mgcp_version, tvb,
1190 tvb_previous_offset, tokenlen,
1191 tvb_format_text(tvb,tvb_previous_offset,
1195 if(tvb_current_offset < tvb_len){
1196 tvb_previous_offset = tvb_skip_wsp(tvb, tvb_current_offset,
1200 } while( tvb_current_offset < tvb_len && tvb_previous_offset < tvb_len
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.
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.
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);
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
1234 conversation = find_conversation(pinfo->fd->num, &null_address,
1235 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1236 pinfo->destport, 0);
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);
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;
1258 delta.nsecs+=1000000000;
1261 proto_tree_add_time(tree, hf_mgcp_time, tvb, 0, 0,
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
1269 mgcp_call->rsp_num = pinfo->fd->num;
1271 /* We have seen a response to this call - but was it
1273 if (mgcp_call->rsp_num != pinfo->fd->num) {
1274 /* No, so it's a duplicate response.
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);
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);
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.
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.
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);
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
1321 conversation = find_conversation(pinfo->fd->num, &pinfo->src,
1322 &null_address, pinfo->ptype, pinfo->srcport,
1323 pinfo->destport, 0);
1325 if (conversation == NULL) {
1326 /* It's not part of any conversation - create a new
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);
1333 conversation = conversation_new(pinfo->fd->num, &pinfo->src,
1334 &null_address, pinfo->ptype, pinfo->srcport,
1335 pinfo->destport, 0);
1339 /* prepare the key data */
1340 mgcp_call_key.transid = mi->transid;
1341 mgcp_call_key.conversation = conversation;
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
1349 if (pinfo->fd->num != mgcp_call->req_num) {
1350 /* No, so it's a duplicate request.
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);
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);
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);
1383 g_hash_table_insert(mgcp_calls, new_mgcp_call_key, mgcp_call);
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);
1395 mi->mgcp_type = mgcp_type;
1397 mi->req_time.secs=mgcp_call->req_time.secs;
1398 mi->req_time.nsecs=mgcp_call->req_time.nsecs;
1401 tap_queue_packet(mgcp_tap, pinfo, mi);
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.
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.
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,
1425 tvb_len = tvb_length(tvb);
1427 tvb_current_len = tvb_length_remaining(tvb,tvb_linebegin);
1428 tvb_lineend = tvb_linebegin;
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);
1439 my_proto_tree_add_string = proto_tree_add_string_hidden;
1440 mgcp_param_tree = tree;
1441 mgcp_param_ti = NULL;
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,
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);
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,
1460 tvb_linebegin = tvb_lineend;
1466 dissect_mgcp_connectionparams(proto_tree *parent_tree, tvbuff_t *tvb, gint offset, gint param_type_len, gint param_val_len)
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;
1474 gchar *tokenline = NULL;
1475 gchar **tokens = NULL;
1476 gchar **typval = NULL;
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);
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;
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;
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]));
1537 if (my_proto_tree_add_text) proto_tree_add_text(tree, tvb, offset, tokenlen, "Unknown parameter: %s", tokens[i]);
1540 if (my_proto_tree_add_text) proto_tree_add_text(tree, tvb, offset, tokenlen, "Malformed parameter: %s", tokens[i]);
1542 offset += tokenlen+1; /* 1 extra for the delimiter */
1550 * tvb_skip_wsp - Returns the position in tvb of the first non-whitespace
1551 * character following offset or offset + maxlength -1 whichever
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
1560 * Returns: The position in tvb of the first non-whitespace
1561 * character following offset or offset + maxlength -1 whichever
1564 static gint tvb_skip_wsp(tvbuff_t* tvb, gint offset, gint maxlength){
1565 gint counter = offset;
1566 gint end = offset + maxlength,tvb_len;
1568 tvb_len = tvb_length(tvb);
1569 end = offset + maxlength;
1573 for(counter = offset; counter < end &&
1574 ((tempchar = tvb_get_guint8(tvb,counter)) == ' ' ||
1575 tempchar == '\t');counter++);
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.
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
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.
1593 * next_offset - The location to write the offset of first character
1594 * FOLLOWING the null line.
1596 * Returns: The length from offset to the first character BEFORE
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;
1604 tvb_linebegin = offset;
1605 tvb_lineend = tvb_linebegin;
1607 /* Simple setup to allow for the traditional -1 search to the end
1611 tvb_current_len = len;
1614 tvb_current_len = tvb_length_remaining(tvb,offset);
1616 maxoffset = (tvb_current_len - 1) + offset;
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.
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);
1628 while( tempchar != '\r' && tempchar != '\n' &&
1629 tvb_lineend <= maxoffset);
1631 *next_offset = tvb_lineend;
1633 if( tvb_lineend <= maxoffset ) {
1634 tvb_current_len = tvb_linebegin - offset;
1637 tvb_current_len = tvb_length_remaining(tvb,offset);
1640 return (tvb_current_len);
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.
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
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.
1657 * next_offset - The location to write the offset of first character
1658 * FOLLOWING the dot line.
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.
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;
1669 tvb_current_offset = offset;
1670 tvb_current_len = len;
1671 tvb_len = tvb_length(tvb);
1674 maxoffset = ( tvb_len - 1 );
1677 maxoffset = (len - 1 ) + offset;
1679 tvb_current_offset = offset -1;
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;
1685 * if we didn't find a . then break out of the loop
1687 if(tvb_current_offset == -1){
1690 /* do we have and characters following the . ? */
1691 if( tvb_current_offset < maxoffset ) {
1692 tempchar = tvb_get_guint8(tvb,tvb_current_offset+1);
1694 * are the characters that follow the dot a newline or carriage return ?
1696 if(tempchar == '\r' || tempchar == '\n'){
1698 * do we have any charaters that proceed the . ?
1700 if( tvb_current_offset == 0 ){
1704 tempchar = tvb_get_guint8(tvb,tvb_current_offset-1);
1706 * are the characters that follow the dot a newline or a carriage
1709 if(tempchar == '\r' || tempchar == '\n'){
1715 else if ( tvb_current_offset == maxoffset ) {
1716 if( tvb_current_offset == 0 ){
1720 tempchar = tvb_get_guint8(tvb,tvb_current_offset-1);
1721 if(tempchar == '\r' || tempchar == '\n'){
1726 } while (tvb_current_offset < maxoffset);
1728 * so now we either have the tvb_current_offset of a . in a dot line
1729 * or a tvb_current_offset of -1
1731 if(tvb_current_offset == -1){
1732 tvb_current_offset = maxoffset +1;
1733 *next_offset = maxoffset + 1;
1736 tvb_find_line_end(tvb,tvb_current_offset,tvb_current_len,next_offset,FALSE);
1739 if( tvb_current_offset == offset ){
1740 tvb_current_len = -1;
1743 tvb_current_len = tvb_current_offset - offset;
1745 return tvb_current_len;
1748 /* Start the functions we need for the plugin stuff */
1750 #ifndef ENABLE_STATIC
1752 G_MODULE_EXPORT void
1753 plugin_reg_handoff(void){
1754 proto_reg_handoff_mgcp();
1757 G_MODULE_EXPORT void
1758 new_plugin_init(void)
1760 /* register the new protocol, protocol fields, and subtrees */
1761 if (proto_mgcp == -1) { /* execute protocol initialization only once */
1762 proto_register_mgcp();
1768 /* End the functions we need for plugin stuff */