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/
10 * www.iana.org/assignments/mgcp-localconnectionoptions
14 * Copyright (c) 2000 by Ed Warnicke <hagbard@physics.rutgers.edu>
15 * Copyright (c) 2004 by Thomas Anders <thomas.anders [AT] blue-cable.de>
17 * Ethereal - Network traffic analyzer
18 * By Gerald Combs <gerald@ethereal.com>
19 * Copyright 1999 Gerald Combs
21 * This program is free software; you can redistribute it and/or
22 * modify it under the terms of the GNU General Public License
23 * as published by the Free Software Foundation; either version 2
24 * of the License, or (at your option) any later version.
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
33 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
40 #include "moduleinfo.h"
45 #include <epan/packet.h>
46 #include <epan/proto.h>
47 #include <epan/prefs.h>
48 #include <epan/conversation.h>
50 #include "packet-mgcp.h"
53 G_MODULE_EXPORT const gchar version[] = VERSION;
56 #define TCP_PORT_MGCP_GATEWAY 2427
57 #define UDP_PORT_MGCP_GATEWAY 2427
58 #define TCP_PORT_MGCP_CALLAGENT 2727
59 #define UDP_PORT_MGCP_CALLAGENT 2727
61 void proto_reg_handoff_mgcp(void);
64 /* Define the mgcp proto */
65 static int proto_mgcp = -1;
67 /* Define many many headers for mgcp */
68 static int hf_mgcp_req = -1;
69 static int hf_mgcp_req_verb = -1;
70 static int hf_mgcp_req_endpoint = -1;
71 static int hf_mgcp_req_frame = -1;
72 static int hf_mgcp_rsp = -1;
73 static int hf_mgcp_rsp_frame = -1;
74 static int hf_mgcp_time = -1;
75 static int hf_mgcp_transid = -1;
76 static int hf_mgcp_version = -1;
77 static int hf_mgcp_rsp_rspcode = -1;
78 static int hf_mgcp_rsp_rspstring = -1;
79 static int hf_mgcp_params = -1;
80 static int hf_mgcp_param_rspack = -1;
81 static int hf_mgcp_param_bearerinfo = -1;
82 static int hf_mgcp_param_callid = -1;
83 static int hf_mgcp_param_connectionid = -1;
84 static int hf_mgcp_param_secondconnectionid = -1;
85 static int hf_mgcp_param_notifiedentity = -1;
86 static int hf_mgcp_param_requestid = -1;
87 static int hf_mgcp_param_localconnoptions = -1;
88 static int hf_mgcp_param_localconnoptions_p = -1;
89 static int hf_mgcp_param_localconnoptions_a = -1;
90 static int hf_mgcp_param_localconnoptions_s = -1;
91 static int hf_mgcp_param_localconnoptions_e = -1;
92 static int hf_mgcp_param_localconnoptions_scrtp = -1;
93 static int hf_mgcp_param_localconnoptions_scrtcp = -1;
94 static int hf_mgcp_param_localconnoptions_b = -1;
95 static int hf_mgcp_param_localconnoptions_esccd = -1;
96 static int hf_mgcp_param_localconnoptions_escci = -1;
97 static int hf_mgcp_param_localconnoptions_dqgi = -1;
98 static int hf_mgcp_param_localconnoptions_dqrd = -1;
99 static int hf_mgcp_param_localconnoptions_dqri = -1;
100 static int hf_mgcp_param_localconnoptions_dqrr = -1;
101 static int hf_mgcp_param_localconnoptions_k = -1;
102 static int hf_mgcp_param_localconnoptions_gc = -1;
103 static int hf_mgcp_param_localconnoptions_fmtp = -1;
104 static int hf_mgcp_param_localconnoptions_nt = -1;
105 static int hf_mgcp_param_localconnoptions_ofmtp = -1;
106 static int hf_mgcp_param_localconnoptions_r = -1;
107 static int hf_mgcp_param_localconnoptions_t = -1;
108 static int hf_mgcp_param_localconnoptions_rcnf = -1;
109 static int hf_mgcp_param_localconnoptions_rdir = -1;
110 static int hf_mgcp_param_localconnoptions_rsh = -1;
111 static int hf_mgcp_param_connectionmode = -1;
112 static int hf_mgcp_param_reqevents = -1;
113 static int hf_mgcp_param_restartmethod = -1;
114 static int hf_mgcp_param_restartdelay = -1;
115 static int hf_mgcp_param_signalreq = -1;
116 static int hf_mgcp_param_digitmap = -1;
117 static int hf_mgcp_param_observedevent = -1;
118 static int hf_mgcp_param_connectionparam = -1;
119 static int hf_mgcp_param_connectionparam_ps = -1;
120 static int hf_mgcp_param_connectionparam_os = -1;
121 static int hf_mgcp_param_connectionparam_pr = -1;
122 static int hf_mgcp_param_connectionparam_or = -1;
123 static int hf_mgcp_param_connectionparam_pl = -1;
124 static int hf_mgcp_param_connectionparam_ji = -1;
125 static int hf_mgcp_param_connectionparam_la = -1;
126 static int hf_mgcp_param_connectionparam_pcrps = -1;
127 static int hf_mgcp_param_connectionparam_pcros = -1;
128 static int hf_mgcp_param_connectionparam_pcrpl = -1;
129 static int hf_mgcp_param_connectionparam_pcrji = -1;
130 static int hf_mgcp_param_connectionparam_x = -1;
131 static int hf_mgcp_param_reasoncode = -1;
132 static int hf_mgcp_param_eventstates = -1;
133 static int hf_mgcp_param_specificendpoint = -1;
134 static int hf_mgcp_param_secondendpointid = -1;
135 static int hf_mgcp_param_reqinfo = -1;
136 static int hf_mgcp_param_quarantinehandling = -1;
137 static int hf_mgcp_param_detectedevents = -1;
138 static int hf_mgcp_param_capabilities = -1;
139 static int hf_mgcp_param_maxmgcpdatagram = -1;
140 static int hf_mgcp_param_packagelist = -1;
141 static int hf_mgcp_param_extension = -1;
142 static int hf_mgcp_param_extension_critical = -1;
143 static int hf_mgcp_param_invalid = -1;
144 static int hf_mgcp_messagecount = -1;
145 static int hf_mgcp_dup = -1;
146 static int hf_mgcp_req_dup = -1;
147 static int hf_mgcp_rsp_dup = -1;
149 static const value_string mgcp_return_code_vals[] = {
150 {000, "Response Acknowledgement"},
151 {100, "The transaction is currently being executed. An actual completion message will follow on later."},
152 {101, "The transaction has been queued for execution. An actual completion message will follow later."},
153 {200, "The requested transaction was executed normally."},
154 {250, "The connection was deleted."},
155 {400, "The transaction could not be executed, due to a transient error."},
156 {401, "The phone is already off hook"},
157 {402, "The phone is already on hook"},
158 {403, "The transaction could not be executed, because the endpoint does not have sufficient resources at this time"},
159 {404, "Insufficient bandwidth at this time"},
160 {405, "The transaction could not be executed, because the endpoint is \"restarting\"."},
161 {406, "Transaction time-out. The transaction did not complete in a reasonable period of time and has been aborted."},
162 {407, "Transaction aborted. The transaction was aborted by some external action, e.g., a ModifyConnection command aborted by a DeleteConnection command."},
163 {409, "The transaction could not be executed because of internal overload."},
164 {410, "No endpoint available. A valid \"any of\" wildcard was used, however there was no endpoint available to satisfy the request."},
165 {500, "The transaction could not be executed, because the endpoint is unknown."},
166 {501, "The transaction could not be executed, because the endpoint is not ready."},
167 {502, "The transaction could not be executed, because the endpoint does not have sufficient resources"},
168 {503, "\"All of\" wildcard too complicated."},
169 {504, "Unknown or unsupported command."},
170 {505, "Unsupported RemoteConnectionDescriptor."},
171 {506, "Unable to satisfy both LocalConnectionOptions and RemoteConnectionDescriptor."},
172 {507, "Unsupported functionality."},
173 {508, "Unknown or unsupported quarantine handling."},
174 {509, "Error in RemoteConnectionDescriptor."},
175 {510, "The transaction could not be executed, because a protocol error was detected."},
176 {511, "The transaction could not be executed, because the command contained an unrecognized extension."},
177 {512, "The transaction could not be executed, because the gateway is not equipped to detect one of the requested events."},
178 {513, "The transaction could not be executed, because the gateway is not equipped to generate one of the requested signals."},
179 {514, "The transaction could not be executed, because the gateway cannot send the specified announcement."},
180 {515, "The transaction refers to an incorrect connection-id (may have been already deleted)"},
181 {516, "The transaction refers to an unknown call-id."},
182 {517, "Unsupported or invalid mode."},
183 {518, "Unsupported or unknown package."},
184 {519, "Endpoint does not have a digit map."},
185 {520, "The transaction could not be executed, because the endpoint is 'restarting'."},
186 {521, "Endpoint redirected to another Call Agent."},
187 {522, "No such event or signal."},
188 {523, "Unknown action or illegal combination of actions"},
189 {524, "Internal inconsistency in LocalConnectionOptions"},
190 {525, "Unknown extension in LocalConnectionOptions"},
191 {526, "Insufficient bandwidth"},
192 {527, "Missing RemoteConnectionDescriptor"},
193 {528, "Incompatible protocol version"},
194 {529, "Internal hardware failure"},
195 {530, "CAS signaling protocol error."},
196 {531, "failure of a grouping of trunks (e.g. facility failure)."},
197 {532, "Unsupported value(s) in LocalConnectionOptions."},
198 {533, "Response too large."},
199 {534, "Codec negotiation failure."},
200 {535, "Packetization period not supported"},
201 {536, "Unknown or unsupported RestartMethod"},
202 {537, "Unknown or unsupported digit map extension"},
203 {538, "Event/signal parameter error (e.g., missing, erroneous, unsupported, unknown, etc.)"},
204 {539, "Invalid or unsupported command parameter."},
205 {540, "Per endpoint connection limit exceeded."},
206 {541, "Invalid or unsupported LocalConnectionOptions"},
210 /* TODO: add/use when tested/have capture to test with */
212 static const value_string mgcp_reason_code_vals[] = {
213 {0, "Endpoint state is normal"},
214 {900, "Endpoint malfunctioning."},
215 {901, "Endpoint taken out-of-service."},
216 {902, "Loss of lower layer connectivity (e.g., downstream sync)."},
217 {903, "QoS resource reservation was lost."},
218 {904, "Manual intervention."},
219 {905, "Facility failure (e.g., DS-0 failure)."},
226 * Define the trees for mgcp
227 * We need one for MGCP itself, one for the MGCP paramters and one
228 * for each of the dissected parameters
230 static int ett_mgcp = -1;
231 static int ett_mgcp_param = -1;
232 static int ett_mgcp_param_connectionparam = -1;
233 static int ett_mgcp_param_localconnectionoptions = -1;
236 * Define the tap for mgcp
238 static int mgcp_tap = -1;
241 * Here are the global variables associated with
242 * the various user definable characteristics of the dissection
244 * MGCP has two kinds of "agents", gateways and callagents. Callagents
245 * control gateways in a master/slave sort of arrangement. Since gateways
246 * and callagents have different well known ports and could both
247 * operate under either udp or tcp we have rather a lot of port info to
250 * global_mgcp_raw_text determines whether we are going to display
251 * the raw text of the mgcp message, much like the HTTP dissector does.
254 static int global_mgcp_gateway_tcp_port = TCP_PORT_MGCP_GATEWAY;
255 static int global_mgcp_gateway_udp_port = UDP_PORT_MGCP_GATEWAY;
256 static int global_mgcp_callagent_tcp_port = TCP_PORT_MGCP_CALLAGENT;
257 static int global_mgcp_callagent_udp_port = UDP_PORT_MGCP_CALLAGENT;
258 static gboolean global_mgcp_raw_text = FALSE;
259 static gboolean global_mgcp_message_count = FALSE;
262 * Variables to allow for proper deletion of dissector registration when
263 * the user changes port from the gui.
265 static int gateway_tcp_port = 0;
266 static int gateway_udp_port = 0;
267 static int callagent_tcp_port = 0;
268 static int callagent_udp_port = 0;
270 /* Some basic utility functions that are specific to this dissector */
271 static gboolean is_mgcp_verb(tvbuff_t *tvb, gint offset, gint maxlength, const gchar **verb_name);
272 static gboolean is_mgcp_rspcode(tvbuff_t *tvb, gint offset, gint maxlength);
273 static gint tvb_parse_param(tvbuff_t *tvb, gint offset, gint maxlength, int** hf);
276 * The various functions that either dissect some
277 * subpart of MGCP. These aren't really proto dissectors but they
278 * are written in the same style.
280 static void dissect_mgcp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
281 proto_tree *mgcp_tree, proto_tree *ti);
282 static void dissect_mgcp_firstline(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
283 static void dissect_mgcp_params(tvbuff_t *tvb, proto_tree *tree);
284 static void dissect_mgcp_connectionparams(proto_tree *parent_tree, tvbuff_t *tvb,
285 gint offset, gint param_type_len,
287 static void dissect_mgcp_localconnectionoptions(proto_tree *parent_tree, tvbuff_t *tvb,
288 gint offset, gint param_type_len,
291 static void mgcp_raw_text_add(tvbuff_t *tvb, proto_tree *tree);
294 * Some functions which should be moved to a library
295 * as I think that people may find them of general usefulness.
297 static gint tvb_skip_wsp(tvbuff_t* tvb, gint offset, gint maxlength);
298 static gint tvb_find_null_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset);
299 static gint tvb_find_dot_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset);
300 static gboolean is_rfc2234_alpha(guint8 c);
302 static dissector_handle_t sdp_handle;
306 * Init Hash table stuff
309 typedef struct _mgcp_call_info_key
312 conversation_t *conversation;
313 } mgcp_call_info_key;
315 static GMemChunk *mgcp_call_info_key_chunk;
316 static GMemChunk *mgcp_call_info_value_chunk;
317 static GHashTable *mgcp_calls;
320 static gint mgcp_call_equal(gconstpointer k1, gconstpointer k2)
322 const mgcp_call_info_key* key1 = (const mgcp_call_info_key*) k1;
323 const mgcp_call_info_key* key2 = (const mgcp_call_info_key*) k2;
325 return (key1->transid == key2->transid &&
326 key1->conversation == key2->conversation);
329 /* Calculate a hash key */
330 static guint mgcp_call_hash(gconstpointer k)
332 const mgcp_call_info_key* key = (const mgcp_call_info_key*) k;
334 return key->transid + key->conversation->index;
339 /************************************************************************
340 * dissect_mgcp - The dissector for the Media Gateway Control Protocol
341 ************************************************************************/
342 static void dissect_mgcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
345 guint32 num_messages;
346 gint tvb_sectionend,tvb_sectionbegin, tvb_len, tvb_current_len;
347 proto_tree *mgcp_tree, *ti;
348 const gchar *verb_name = "";
350 /* Initialize variables */
352 tvb_sectionbegin = tvb_sectionend;
354 tvb_len = tvb_length(tvb);
355 tvb_current_len = tvb_len;
361 * Set the columns now, so that they'll be set correctly if we throw
362 * an exception. We can set them later as well....
364 if (check_col(pinfo->cinfo, COL_PROTOCOL))
365 col_add_str(pinfo->cinfo, COL_PROTOCOL, "MGCP");
366 if (check_col(pinfo->cinfo, COL_INFO))
367 col_clear(pinfo->cinfo, COL_INFO);
370 * Check to see whether we're really dealing with MGCP by looking
371 * for a valid MGCP verb or response code. This isn't infallible,
372 * but its cheap and its better than nothing.
374 if (is_mgcp_verb(tvb,0,tvb_len, &verb_name) || is_mgcp_rspcode(tvb,0,tvb_len))
377 * Loop through however many mgcp messages may be stuck in
378 * this packet using piggybacking
385 /* Create our mgcp subtree */
386 ti = proto_tree_add_item(tree,proto_mgcp,tvb,0,0, FALSE);
387 mgcp_tree = proto_item_add_subtree(ti, ett_mgcp);
390 sectionlen = tvb_find_dot_line(tvb, tvb_sectionbegin, -1, &tvb_sectionend);
391 if (sectionlen != -1)
393 dissect_mgcp_message(tvb_new_subset(tvb, tvb_sectionbegin,
395 pinfo, tree, mgcp_tree,ti);
396 tvb_sectionbegin = tvb_sectionend;
402 } while (tvb_sectionend < tvb_len);
406 proto_tree_add_uint_hidden(mgcp_tree, hf_mgcp_messagecount, tvb,
407 0 ,0 , num_messages);
411 * Add our column information after dissecting SDP
412 * in order to prevent the column info changing to reflect the SDP
413 * (when showing message count)
415 tvb_sectionbegin = 0;
416 if (check_col(pinfo->cinfo, COL_PROTOCOL))
418 if (global_mgcp_message_count == TRUE )
420 if (num_messages > 1)
422 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "MGCP (%i messages)",num_messages);
426 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "MGCP (%i message)",num_messages);
431 if (check_col(pinfo->cinfo, COL_INFO))
433 sectionlen = tvb_find_line_end(tvb, tvb_sectionbegin,-1,
434 &tvb_sectionend,FALSE);
435 col_prepend_fstr(pinfo->cinfo, COL_INFO, "%s",
436 tvb_format_text(tvb, tvb_sectionbegin, sectionlen));
441 #define MAX_MGCP_MESSAGES_IN_PACKET 5
442 static mgcp_info_t pi_arr[MAX_MGCP_MESSAGES_IN_PACKET];
443 static int pi_current = 0;
444 static mgcp_info_t *mi;
446 /* Dissect an individual MGCP message */
447 static void dissect_mgcp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
448 proto_tree *mgcp_tree, proto_tree *ti)
450 /* Declare variables */
452 gint tvb_sectionend,tvb_sectionbegin, tvb_len, tvb_current_len;
454 const gchar *verb_name = "";
456 /* Initialise stat info for passing to tap */
458 if (pi_current == MAX_MGCP_MESSAGES_IN_PACKET)
460 /* Overwrite info in first struct if run out of space... */
463 mi = &pi_arr[pi_current];
466 mi->mgcp_type = MGCP_OTHERS;
469 mi->req_time.secs = 0;
470 mi->req_time.nsecs = 0;
471 mi->is_duplicate = FALSE;
472 mi->request_available = FALSE;
474 mi->endpointId = NULL;
475 mi->observedEvents = NULL;
477 mi->signalReq = NULL;
478 mi->hasDigitMap = FALSE;
480 /* Initialize variables */
482 tvb_sectionbegin = tvb_sectionend;
484 tvb_len = tvb_length(tvb);
485 tvb_current_len = tvb_len;
488 * Check to see whether we're really dealing with MGCP by looking
489 * for a valid MGCP verb or response code. This isn't infallible,
490 * but its cheap and its better than nothing.
492 if (is_mgcp_verb(tvb,0,tvb_len,&verb_name) || is_mgcp_rspcode(tvb,0,tvb_len))
494 /* dissect first line */
495 tvb_sectionbegin = 0;
496 tvb_current_len = tvb_len;
497 tvb_sectionend = tvb_sectionbegin;
498 sectionlen = tvb_find_line_end(tvb,0,-1,&tvb_sectionend,FALSE);
501 dissect_mgcp_firstline(tvb_new_subset(tvb, tvb_sectionbegin,
502 sectionlen,-1), pinfo,
505 tvb_sectionbegin = tvb_sectionend;
508 if (tvb_sectionbegin < tvb_len)
510 sectionlen = tvb_find_null_line(tvb, tvb_sectionbegin, -1,
514 dissect_mgcp_params(tvb_new_subset(tvb, tvb_sectionbegin, sectionlen, -1),
516 tvb_sectionbegin = tvb_sectionend;
520 /* Set the mgcp payload length correctly so we don't include any
522 sectionlen = tvb_sectionend;
523 proto_item_set_len(ti,sectionlen);
525 /* Display the raw text of the mgcp message if desired */
527 /* Do we want to display the raw text of our MGCP packet? */
528 if (global_mgcp_raw_text)
531 mgcp_raw_text_add(tvb, mgcp_tree);
534 /* Dissect sdp payload */
535 if (tvb_sectionend < tvb_len)
537 next_tvb = tvb_new_subset(tvb, tvb_sectionend, -1, -1);
538 call_dissector(sdp_handle, next_tvb, pinfo, tree);
545 * Add the raw text of the message to the dissect tree if appropriate
546 * preferences are specified.
548 static void mgcp_raw_text_add(tvbuff_t *tvb, proto_tree *tree)
550 gint tvb_linebegin,tvb_lineend,tvb_len,linelen;
553 tvb_len = tvb_length(tvb);
557 tvb_find_line_end(tvb,tvb_linebegin,-1,&tvb_lineend,FALSE);
558 linelen = tvb_lineend - tvb_linebegin;
559 proto_tree_add_text(tree, tvb, tvb_linebegin, linelen, "%s",
560 tvb_format_text(tvb, tvb_linebegin, linelen));
561 tvb_linebegin = tvb_lineend;
562 } while (tvb_lineend < tvb_len);
565 /* Discard and init any state we've saved */
566 static void mgcp_init_protocol(void)
568 if (mgcp_calls != NULL)
570 g_hash_table_destroy(mgcp_calls);
573 if (mgcp_call_info_key_chunk != NULL)
575 g_mem_chunk_destroy(mgcp_call_info_key_chunk);
576 mgcp_call_info_key_chunk = NULL;
578 if (mgcp_call_info_value_chunk != NULL)
580 g_mem_chunk_destroy(mgcp_call_info_value_chunk);
581 mgcp_call_info_value_chunk = NULL;
584 mgcp_calls = g_hash_table_new(mgcp_call_hash, mgcp_call_equal);
585 mgcp_call_info_key_chunk = g_mem_chunk_new("call_info_key_chunk",
586 sizeof(mgcp_call_info_key),
587 200 * sizeof(mgcp_call_info_key),
589 mgcp_call_info_value_chunk = g_mem_chunk_new("call_info_value_chunk",
591 200 * sizeof(mgcp_call_t),
595 /* Register all the bits needed with the filtering engine */
596 void proto_register_mgcp(void)
598 static hf_register_info hf[] =
601 { "Request", "mgcp.req", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
602 "True if MGCP request", HFILL }},
604 { "Response", "mgcp.rsp", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
605 "TRUE if MGCP response", HFILL }},
606 { &hf_mgcp_req_frame,
607 { "Request Frame", "mgcp.reqframe", FT_FRAMENUM, BASE_NONE, NULL, 0,
608 "Request Frame", HFILL }},
609 { &hf_mgcp_rsp_frame,
610 { "Response Frame", "mgcp.rspframe", FT_FRAMENUM, BASE_NONE, NULL, 0,
611 "Response Frame", HFILL }},
613 { "Time from request", "mgcp.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0,
614 "Timedelta between Request and Response", HFILL }},
616 { "Verb", "mgcp.req.verb", FT_STRING, BASE_DEC, NULL, 0x0,
617 "Name of the verb", HFILL }},
618 { &hf_mgcp_req_endpoint,
619 { "Endpoint", "mgcp.req.endpoint", FT_STRING, BASE_DEC, NULL, 0x0,
620 "Endpoint referenced by the message", HFILL }},
622 { "Transaction ID", "mgcp.transid", FT_STRING, BASE_DEC, NULL, 0x0,
623 "Transaction ID of this message", HFILL }},
625 { "Version", "mgcp.version", FT_STRING, BASE_DEC, NULL, 0x0,
626 "MGCP Version", HFILL }},
627 { &hf_mgcp_rsp_rspcode,
628 { "Response Code", "mgcp.rsp.rspcode", FT_UINT32, BASE_DEC, VALS(mgcp_return_code_vals), 0x0,
629 "Response Code", HFILL }},
630 { &hf_mgcp_rsp_rspstring,
631 { "Response String", "mgcp.rsp.rspstring", FT_STRING, BASE_DEC, NULL, 0x0,
632 "Response String", HFILL }},
634 { "Parameters", "mgcp.params", FT_NONE, 0, NULL, 0x0,
635 "MGCP parameters", HFILL }},
636 { &hf_mgcp_param_rspack,
637 { "ResponseAck (K)", "mgcp.param.rspack", FT_STRING, BASE_DEC, NULL, 0x0,
638 "Response Ack", HFILL }},
639 { &hf_mgcp_param_bearerinfo,
640 { "BearerInformation (B)", "mgcp.param.bearerinfo", FT_STRING, BASE_DEC, NULL, 0x0,
641 "Bearer Information", HFILL }},
642 { &hf_mgcp_param_callid,
643 { "CallId (C)", "mgcp.param.callid", FT_STRING, BASE_DEC, NULL, 0x0,
645 { &hf_mgcp_param_connectionid,
646 {"ConnectionIdentifier (I)", "mgcp.param.connectionid", FT_STRING, BASE_DEC, NULL, 0x0,
647 "Connection Identifier", HFILL }},
648 { &hf_mgcp_param_secondconnectionid,
649 { "SecondConnectionID (I2)", "mgcp.param.secondconnectionid", FT_STRING, BASE_DEC, NULL, 0x0,
650 "Second Connection Identifier", HFILL }},
651 { &hf_mgcp_param_notifiedentity,
652 { "NotifiedEntity (N)", "mgcp.param.notifiedentity", FT_STRING, BASE_DEC, NULL, 0x0,
653 "Notified Entity", HFILL }},
654 { &hf_mgcp_param_requestid,
655 { "RequestIdentifier (X)", "mgcp.param.requestid", FT_STRING, BASE_DEC, NULL, 0x0,
656 "Request Identifier", HFILL }},
657 { &hf_mgcp_param_localconnoptions,
658 { "LocalConnectionOptions (L)", "mgcp.param.localconnectionoptions", FT_STRING, BASE_DEC, NULL, 0x0,
659 "Local Connection Options", HFILL }},
660 { &hf_mgcp_param_localconnoptions_p,
661 { "Packetization period (p)", "mgcp.param.localconnectionoptions.p", FT_UINT32, BASE_DEC, NULL, 0x0,
662 "Packetization period", HFILL }},
663 { &hf_mgcp_param_localconnoptions_a,
664 { "Codecs (a)", "mgcp.param.localconnectionoptions.a", FT_STRING, BASE_DEC, NULL, 0x0,
666 { &hf_mgcp_param_localconnoptions_s,
667 { "Silence Suppression (s)", "mgcp.param.localconnectionoptions.s", FT_STRING, BASE_DEC, NULL, 0x0,
668 "Silence Suppression", HFILL }},
669 { &hf_mgcp_param_localconnoptions_e,
670 { "Echo Cancellation (e)", "mgcp.param.localconnectionoptions.e", FT_STRING, BASE_DEC, NULL, 0x0,
671 "Echo Cancellation", HFILL }},
672 { &hf_mgcp_param_localconnoptions_scrtp,
673 { "RTP ciphersuite (sc-rtp)", "mgcp.param.localconnectionoptions.scrtp", FT_STRING, BASE_DEC, NULL, 0x0,
674 "RTP ciphersuite", HFILL }},
675 { &hf_mgcp_param_localconnoptions_scrtcp,
676 { "RTCP ciphersuite (sc-rtcp)", "mgcp.param.localconnectionoptions.scrtcp", FT_STRING, BASE_DEC, NULL, 0x0,
677 "RTCP ciphersuite", HFILL }},
678 { &hf_mgcp_param_localconnoptions_b,
679 { "Bandwidth (b)", "mgcp.param.localconnectionoptions.b", FT_STRING, BASE_DEC, NULL, 0x0,
680 "Bandwidth", HFILL }},
681 { &hf_mgcp_param_localconnoptions_esccd,
682 { "Content Destination (es-ccd)", "mgcp.param.localconnectionoptions.esccd", FT_STRING, BASE_DEC, NULL, 0x0,
683 "Content Destination", HFILL }},
684 { &hf_mgcp_param_localconnoptions_escci,
685 { "Content Identifier (es-cci)", "mgcp.param.localconnectionoptions.escci", FT_STRING, BASE_DEC, NULL, 0x0,
686 "Content Identifier", HFILL }},
687 { &hf_mgcp_param_localconnoptions_dqgi,
688 { "D-QoS GateID (dq-gi)", "mgcp.param.localconnectionoptions.dqgi", FT_STRING, BASE_DEC, NULL, 0x0,
689 "D-QoS GateID", HFILL }},
690 { &hf_mgcp_param_localconnoptions_dqrd,
691 { "D-QoS Reserve Destination (dq-rd)", "mgcp.param.localconnectionoptions.dqrd", FT_STRING, BASE_DEC, NULL, 0x0,
692 "D-QoS Reserve Destination", HFILL }},
693 { &hf_mgcp_param_localconnoptions_dqri,
694 { "D-QoS Resource ID (dq-ri)", "mgcp.param.localconnectionoptions.dqri", FT_STRING, BASE_DEC, NULL, 0x0,
695 "D-QoS Resource ID", HFILL }},
696 { &hf_mgcp_param_localconnoptions_dqrr,
697 { "D-QoS Resource Reservation (dq-rr)", "mgcp.param.localconnectionoptions.dqrr", FT_STRING, BASE_DEC, NULL, 0x0,
698 "D-QoS Resource Reservation", HFILL }},
699 { &hf_mgcp_param_localconnoptions_k,
700 { "Encryption Key (k)", "mgcp.param.localconnectionoptions.k", FT_STRING, BASE_DEC, NULL, 0x0,
701 "Encryption Key", HFILL }},
702 { &hf_mgcp_param_localconnoptions_gc,
703 { "Gain Control (gc)", "mgcp.param.localconnectionoptions.gc", FT_UINT32, BASE_DEC, NULL, 0x0,
704 "Gain Control", HFILL }},
705 { &hf_mgcp_param_localconnoptions_fmtp,
706 { "Media Format (fmtp)", "mgcp.param.localconnectionoptions.fmtp", FT_STRING, BASE_DEC, NULL, 0x0,
707 "Media Format", HFILL }},
708 { &hf_mgcp_param_localconnoptions_nt,
709 { "Network Type (nt)", "mgcp.param.localconnectionoptions.nt", FT_STRING, BASE_DEC, NULL, 0x0,
710 "Network Type", HFILL }},
711 { &hf_mgcp_param_localconnoptions_ofmtp,
712 { "Optional Media Format (o-fmtp)", "mgcp.param.localconnectionoptions.ofmtp", FT_STRING, BASE_DEC, NULL, 0x0,
713 "Optional Media Format", HFILL }},
714 { &hf_mgcp_param_localconnoptions_r,
715 { "Resource Reservation (r)", "mgcp.param.localconnectionoptions.r", FT_STRING, BASE_DEC, NULL, 0x0,
716 "Resource Reservation", HFILL }},
717 { &hf_mgcp_param_localconnoptions_t,
718 { "Type of Service (r)", "mgcp.param.localconnectionoptions.t", FT_STRING, BASE_DEC, NULL, 0x0,
719 "Type of Service", HFILL }},
720 { &hf_mgcp_param_localconnoptions_rcnf,
721 { "Reservation Confirmation (r-cnf)", "mgcp.param.localconnectionoptions.rcnf", FT_STRING, BASE_DEC, NULL, 0x0,
722 "Reservation Confirmation", HFILL }},
723 { &hf_mgcp_param_localconnoptions_rdir,
724 { "Reservation Direction (r-dir)", "mgcp.param.localconnectionoptions.rdir", FT_STRING, BASE_DEC, NULL, 0x0,
725 "Reservation Direction", HFILL }},
726 { &hf_mgcp_param_localconnoptions_rsh,
727 { "Resource Sharing (r-sh)", "mgcp.param.localconnectionoptions.rsh", FT_STRING, BASE_DEC, NULL, 0x0,
728 "Resource Sharing", HFILL }},
729 { &hf_mgcp_param_connectionmode,
730 { "ConnectionMode (M)", "mgcp.param.connectionmode", FT_STRING, BASE_DEC, NULL, 0x0,
731 "Connection Mode", HFILL }},
732 { &hf_mgcp_param_reqevents,
733 { "RequestedEvents (R)", "mgcp.param.reqevents", FT_STRING, BASE_DEC, NULL, 0x0,
734 "Requested Events", HFILL }},
735 { &hf_mgcp_param_signalreq,
736 { "SignalRequests (S)", "mgcp.param.signalreq", FT_STRING, BASE_DEC, NULL, 0x0,
737 "Signal Request", HFILL }},
738 { &hf_mgcp_param_restartmethod,
739 { "RestartMethod (RM)", "mgcp.param.restartmethod", FT_STRING, BASE_DEC, NULL, 0x0,
740 "Restart Method", HFILL }},
741 { &hf_mgcp_param_restartdelay,
742 { "RestartDelay (RD)", "mgcp.param.restartdelay", FT_STRING, BASE_DEC, NULL, 0x0,
743 "Restart Delay", HFILL }},
744 { &hf_mgcp_param_digitmap,
745 { "DigitMap (D)", "mgcp.param.digitmap", FT_STRING, BASE_DEC, NULL, 0x0,
746 "Digit Map", HFILL }},
747 { &hf_mgcp_param_observedevent,
748 { "ObservedEvents (O)", "mgcp.param.observedevents", FT_STRING, BASE_DEC, NULL, 0x0,
749 "Observed Events", HFILL }},
750 { &hf_mgcp_param_connectionparam,
751 { "ConnectionParameters (P)", "mgcp.param.connectionparam", FT_STRING, BASE_DEC, NULL, 0x0,
752 "Connection Parameters", HFILL }},
753 { &hf_mgcp_param_connectionparam_ps,
754 { "Packets sent (PS)", "mgcp.param.connectionparam.ps", FT_UINT32, BASE_DEC, NULL, 0x0,
755 "Packets sent (P:PS)", HFILL }},
756 { &hf_mgcp_param_connectionparam_os,
757 { "Octets sent (OS)", "mgcp.param.connectionparam.os", FT_UINT32, BASE_DEC, NULL, 0x0,
758 "Octets sent (P:OS)", HFILL }},
759 { &hf_mgcp_param_connectionparam_pr,
760 { "Packets received (PR)", "mgcp.param.connectionparam.pr", FT_UINT32, BASE_DEC, NULL, 0x0,
761 "Packets received (P:PR)", HFILL }},
762 { &hf_mgcp_param_connectionparam_or,
763 { "Octets received (OR)", "mgcp.param.connectionparam.or", FT_UINT32, BASE_DEC, NULL, 0x0,
764 "Octets received (P:OR)", HFILL }},
765 { &hf_mgcp_param_connectionparam_pl,
766 { "Packets lost (PL)", "mgcp.param.connectionparam.pl", FT_UINT32, BASE_DEC, NULL, 0x0,
767 "Packets lost (P:PL)", HFILL }},
768 { &hf_mgcp_param_connectionparam_ji,
769 { "Jitter (JI)", "mgcp.param.connectionparam.ji", FT_UINT32, BASE_DEC, NULL, 0x0,
770 "Average inter-packet arrival jitter in milliseconds (P:JI)", HFILL }},
771 { &hf_mgcp_param_connectionparam_la,
772 { "Latency (LA)", "mgcp.param.connectionparam.la", FT_UINT32, BASE_DEC, NULL, 0x0,
773 "Average latency in milliseconds (P:LA)", HFILL }},
774 { &hf_mgcp_param_connectionparam_pcrps,
775 { "Remote Packets sent (PC/RPS)", "mgcp.param.connectionparam.pcrps", FT_UINT32, BASE_DEC, NULL, 0x0,
776 "Remote Packets sent (P:PC/RPS)", HFILL }},
777 { &hf_mgcp_param_connectionparam_pcros,
778 { "Remote Octets sent (PC/ROS)", "mgcp.param.connectionparam.pcros", FT_UINT32, BASE_DEC, NULL, 0x0,
779 "Remote Octets sent (P:PC/ROS)", HFILL }},
780 { &hf_mgcp_param_connectionparam_pcrpl,
781 { "Remote Packets lost (PC/RPL)", "mgcp.param.connectionparam.pcrpl", FT_UINT32, BASE_DEC, NULL, 0x0,
782 "Remote Packets lost (P:PC/RPL)", HFILL }},
783 { &hf_mgcp_param_connectionparam_pcrji,
784 { "Remote Jitter (PC/RJI)", "mgcp.param.connectionparam.pcrji", FT_UINT32, BASE_DEC, NULL, 0x0,
785 "Remote Jitter (P:PC/RJI)", HFILL }},
786 { &hf_mgcp_param_connectionparam_x,
787 { "Vendor Extension", "mgcp.param.connectionparam.x", FT_STRING, BASE_DEC, NULL, 0x0,
788 "Vendor Extension (P:X-*)", HFILL }},
789 { &hf_mgcp_param_reasoncode,
790 { "ReasonCode (E)", "mgcp.param.reasoncode", FT_STRING, BASE_DEC, NULL, 0x0,
791 "Reason Code", HFILL }},
792 { &hf_mgcp_param_eventstates,
793 { "EventStates (ES)", "mgcp.param.eventstates", FT_STRING, BASE_DEC, NULL, 0x0,
794 "Event States", HFILL }},
795 { &hf_mgcp_param_specificendpoint,
796 { "SpecificEndpointID (Z)", "mgcp.param.specificendpointid", FT_STRING, BASE_DEC, NULL, 0x0,
797 "Specific Endpoint ID", HFILL }},
798 { &hf_mgcp_param_secondendpointid,
799 { "SecondEndpointID (Z2)", "mgcp.param.secondendpointid", FT_STRING, BASE_DEC, NULL, 0x0,
800 "Second Endpoing ID", HFILL }},
801 { &hf_mgcp_param_reqinfo,
802 { "RequestedInfo (F)", "mgcp.param.reqinfo", FT_STRING, BASE_DEC, NULL, 0x0,
803 "Requested Info", HFILL }},
804 { &hf_mgcp_param_quarantinehandling,
805 { "QuarantineHandling (Q)", "mgcp.param.quarantinehandling", FT_STRING, BASE_DEC, NULL, 0x0,
806 "Quarantine Handling", HFILL }},
807 { &hf_mgcp_param_detectedevents,
808 { "DetectedEvents (T)", "mgcp.param.detectedevents", FT_STRING, BASE_DEC, NULL, 0x0,
809 "Detected Events", HFILL }},
810 { &hf_mgcp_param_capabilities,
811 { "Capabilities (A)", "mgcp.param.capabilities", FT_STRING, BASE_DEC, NULL, 0x0,
812 "Capabilities", HFILL }},
813 { &hf_mgcp_param_maxmgcpdatagram,
814 {"MaxMGCPDatagram (MD)", "mgcp.param.maxmgcpdatagram", FT_STRING, BASE_DEC, NULL, 0x0,
815 "Maximum MGCP Datagram size", HFILL }},
816 { &hf_mgcp_param_packagelist,
817 {"PackageList (PL)", "mgcp.param.packagelist", FT_STRING, BASE_DEC, NULL, 0x0,
818 "Package List", HFILL }},
819 { &hf_mgcp_param_extension,
820 { "Extension Parameter (non-critical)", "mgcp.param.extension", FT_STRING, BASE_DEC, NULL, 0x0,
821 "Extension Parameter", HFILL }},
822 { &hf_mgcp_param_extension_critical,
823 { "Extension Parameter (critical)", "mgcp.param.extensioncritical", FT_STRING, BASE_DEC, NULL, 0x0,
824 "Critical Extension Parameter", HFILL }},
825 { &hf_mgcp_param_invalid,
826 { "Invalid Parameter", "mgcp.param.invalid", FT_STRING, BASE_DEC, NULL, 0x0,
827 "Invalid Parameter", HFILL }},
828 { &hf_mgcp_messagecount,
829 { "MGCP Message Count", "mgcp.messagecount", FT_UINT32, BASE_DEC, NULL, 0x0,
830 "Number of MGCP message in a packet", HFILL }},
832 { "Duplicate Message", "mgcp.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
833 "Duplicate Message", HFILL }},
835 { "Duplicate Request", "mgcp.req.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
836 "Duplicate Request", HFILL }},
838 { "Duplicate Response", "mgcp.rsp.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
839 "Duplicate Response", HFILL }},
846 &ett_mgcp_param_connectionparam,
847 &ett_mgcp_param_localconnectionoptions
850 module_t *mgcp_module;
852 /* Register protocol */
853 proto_mgcp = proto_register_protocol("Media Gateway Control Protocol", "MGCP", "mgcp");
854 proto_register_field_array(proto_mgcp, hf, array_length(hf));
855 proto_register_subtree_array(ett, array_length(ett));
856 register_init_routine(&mgcp_init_protocol);
858 /* Register our configuration options */
859 mgcp_module = prefs_register_protocol(proto_mgcp, proto_reg_handoff_mgcp);
861 prefs_register_uint_preference(mgcp_module, "tcp.gateway_port",
862 "MGCP Gateway TCP Port",
863 "Set the UDP port for gateway messages "
864 "(if other than the default of 2427)",
865 10, &global_mgcp_gateway_tcp_port);
867 prefs_register_uint_preference(mgcp_module, "udp.gateway_port",
868 "MGCP Gateway UDP Port",
869 "Set the TCP port for gateway messages "
870 "(if other than the default of 2427)",
871 10, &global_mgcp_gateway_udp_port);
873 prefs_register_uint_preference(mgcp_module, "tcp.callagent_port",
874 "MGCP Callagent TCP Port",
875 "Set the TCP port for callagent messages "
876 "(if other than the default of 2727)",
877 10, &global_mgcp_callagent_tcp_port);
879 prefs_register_uint_preference(mgcp_module, "udp.callagent_port",
880 "MGCP Callagent UDP Port",
881 "Set the UDP port for callagent messages "
882 "(if other than the default of 2727)",
883 10, &global_mgcp_callagent_udp_port);
886 prefs_register_bool_preference(mgcp_module, "display_raw_text",
887 "Display raw text for MGCP message",
888 "Specifies that the raw text of the "
889 "MGCP message should be displayed "
890 "instead of (or in addition to) the "
892 &global_mgcp_raw_text);
894 prefs_register_obsolete_preference(mgcp_module, "display_dissect_tree");
896 prefs_register_bool_preference(mgcp_module, "display_mgcp_message_count",
897 "Display the number of MGCP messages",
898 "Display the number of MGCP messages "
899 "found in a packet in the protocol column.",
900 &global_mgcp_message_count);
902 mgcp_tap = register_tap("mgcp");
905 /* The registration hand-off routine */
906 void proto_reg_handoff_mgcp(void)
908 static int mgcp_prefs_initialized = FALSE;
909 static dissector_handle_t mgcp_handle;
911 /* Get a handle for the SDP dissector. */
912 sdp_handle = find_dissector("sdp");
914 if (!mgcp_prefs_initialized)
916 mgcp_handle = create_dissector_handle(dissect_mgcp, proto_mgcp);
917 mgcp_prefs_initialized = TRUE;
921 dissector_delete("tcp.port", gateway_tcp_port, mgcp_handle);
922 dissector_delete("udp.port", gateway_udp_port, mgcp_handle);
923 dissector_delete("tcp.port", callagent_tcp_port, mgcp_handle);
924 dissector_delete("udp.port", callagent_udp_port, mgcp_handle);
927 /* Set our port number for future use */
928 gateway_tcp_port = global_mgcp_gateway_tcp_port;
929 gateway_udp_port = global_mgcp_gateway_udp_port;
931 callagent_tcp_port = global_mgcp_callagent_tcp_port;
932 callagent_udp_port = global_mgcp_callagent_udp_port;
934 dissector_add("tcp.port", global_mgcp_gateway_tcp_port, mgcp_handle);
935 dissector_add("udp.port", global_mgcp_gateway_udp_port, mgcp_handle);
936 dissector_add("tcp.port", global_mgcp_callagent_tcp_port, mgcp_handle);
937 dissector_add("udp.port", global_mgcp_callagent_udp_port, mgcp_handle);
941 * is_mgcp_verb - A function for determining whether there is a
942 * MGCP verb at offset in tvb
945 * tvb - The tvbuff in which we are looking for an MGCP verb
946 * offset - The offset in tvb at which we are looking for a MGCP verb
947 * maxlength - The maximum distance from offset we may look for the
948 * characters that make up a MGCP verb.
949 * verb_name - The name for the verb code found (output)
951 * Return: TRUE if there is an MGCP verb at offset in tvb, otherwise FALSE
953 static gboolean is_mgcp_verb(tvbuff_t *tvb, gint offset, gint maxlength, const gchar **verb_name)
955 int returnvalue = FALSE;
958 /* Read the string into 'word' and see if it looks like the start of a verb */
959 if ((maxlength >= 4) && tvb_get_nstringz0(tvb, offset, sizeof(word), word))
961 if (((strncasecmp(word, "EPCF", 4) == 0) && (*verb_name = "EndpointConfiguration|")) ||
962 ((strncasecmp(word, "CRCX", 4) == 0) && (*verb_name = "CreateConnection")) ||
963 ((strncasecmp(word, "MDCX", 4) == 0) && (*verb_name = "ModifyConnection")) ||
964 ((strncasecmp(word, "DLCX", 4) == 0) && (*verb_name = "DeleteConnection")) ||
965 ((strncasecmp(word, "RQNT", 4) == 0) && (*verb_name = "NotificationRequest")) ||
966 ((strncasecmp(word, "NTFY", 4) == 0) && (*verb_name = "Notify")) ||
967 ((strncasecmp(word, "AUEP", 4) == 0) && (*verb_name = "AuditEndpoint")) ||
968 ((strncasecmp(word, "AUCX", 4) == 0) && (*verb_name = "AuditConnection")) ||
969 ((strncasecmp(word, "RSIP", 4) == 0) && (*verb_name = "RestartInProgress")) ||
970 ((strncasecmp(word, "MESG", 4) == 0) && (*verb_name = "Message")) ||
971 (word[0] == 'X' && is_rfc2234_alpha(word[1]) && is_rfc2234_alpha(word[2]) &&
972 is_rfc2234_alpha(word[3]) && (*verb_name = "*Experimental*")))
978 /* May be whitespace after verb code - anything else is an error.. */
979 if (returnvalue && maxlength >= 5)
981 char next = tvb_get_guint8(tvb,4);
982 if ((next != ' ') && (next != '\t'))
992 * is_mgcp_rspcode - A function for determining whether something which
993 * looks roughly like a MGCP response code (3-digit number)
994 * is at 'offset' in tvb
997 * tvb - The tvbuff in which we are looking for an MGCP response code
998 * offset - The offset in tvb at which we are looking for a MGCP response code
999 * maxlength - The maximum distance from offset we may look for the
1000 * characters that make up a MGCP response code.
1002 * Return: TRUE if there is an MGCP response code at offset in tvb,
1005 static gboolean is_mgcp_rspcode(tvbuff_t *tvb, gint offset, gint maxlength)
1007 int returnvalue = FALSE;
1010 /* Do 1st 3 characters look like digits? */
1013 tvb_get_nstringz0(tvb, offset, sizeof(word), word);
1014 if (isdigit(word[0]) && isdigit(word[1]) && isdigit(word[2]))
1020 /* Maybe some white space after the 3rd digit - anything else is an error */
1021 if (returnvalue && maxlength >= 4)
1023 char next = tvb_get_guint8(tvb, 3);
1024 if ((next != ' ') && (next != '\t'))
1026 returnvalue = FALSE;
1034 * is_rfc2234_alpha - Indicates whether the character c is an alphabetical
1035 * character. This function is used instead of
1036 * isalpha because isalpha may deviate from the rfc2234
1037 * definition of ALPHA in some locales.
1040 * c - The character being checked for being an alphabetical character.
1042 * Return: TRUE if c is an upper or lower case alphabetical character,
1045 static gboolean is_rfc2234_alpha(guint8 c)
1047 return ((c <= 'Z' && c >= 'A' ) || (c <= 'z' && c >= 'a'));
1052 * tvb_parse_param - Parse the MGCP param into a type and a value.
1055 * tvb - The tvbuff containing the MGCP param we are to parse.
1056 * offset - The offset in tvb at which we will begin looking for a
1057 * MGCP parameter to parse.
1058 * len - The maximum distance from offset in tvb that we can look for
1059 * an MGCP parameter to parse.
1060 * hf - The place to write a pointer to the integer representing the
1061 * header field associated with the MGCP parameter parsed.
1063 * Returns: The offset in tvb where the value of the MGCP parameter
1066 static gint tvb_parse_param(tvbuff_t* tvb, gint offset, gint len, int** hf)
1068 gint returnvalue = -1, tvb_current_offset,counter;
1069 guint8 tempchar, plus_minus;
1072 tvb_current_offset = offset;
1078 tempchar = tvb_get_guint8(tvb,tvb_current_offset);
1083 *hf = &hf_mgcp_param_rspack;
1086 *hf = &hf_mgcp_param_bearerinfo;
1089 *hf = &hf_mgcp_param_callid;
1092 tvb_current_offset++;
1093 if (len > (tvb_current_offset - offset) &&
1094 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1096 *hf = &hf_mgcp_param_connectionid;
1097 tvb_current_offset--;
1100 if (tempchar == '2')
1102 *hf = &hf_mgcp_param_secondconnectionid;
1106 *hf = &hf_mgcp_param_notifiedentity;
1110 tvb_current_offset++;
1112 /* X: is RequestIdentifier */
1113 if (len > (tvb_current_offset - offset) &&
1114 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1116 *hf = &hf_mgcp_param_requestid;
1117 tvb_current_offset--;
1120 /* X+...: or X-....: are vendor extension parameters */
1122 if (len > (tvb_current_offset - offset) &&
1123 ((plus_minus = tvb_get_guint8(tvb,tvb_current_offset)) == '-' ||
1124 (plus_minus == '+')))
1126 /* Move past + or - */
1127 tvb_current_offset++;
1129 /* Keep going, through possible vendor param name */
1131 ((len > (counter + tvb_current_offset-offset)) &&
1132 (is_rfc2234_alpha(tempchar = tvb_get_guint8(tvb, tvb_current_offset+counter)) ||
1133 isdigit(tempchar))) ;
1136 if (tempchar == ':')
1138 /* Looks like a valid vendor param name */
1139 tvb_current_offset += counter;
1143 *hf = &hf_mgcp_param_extension_critical;
1146 *hf = &hf_mgcp_param_extension;
1153 *hf = &hf_mgcp_param_localconnoptions;
1156 tvb_current_offset++;
1157 if (len > (tvb_current_offset - offset) &&
1158 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1160 *hf = &hf_mgcp_param_connectionmode;
1161 tvb_current_offset--;
1164 if (tempchar == 'D')
1166 *hf = &hf_mgcp_param_maxmgcpdatagram;
1170 tvb_current_offset++;
1171 if (len > (tvb_current_offset - offset) &&
1172 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1174 *hf = &hf_mgcp_param_reqevents;
1175 tvb_current_offset--;
1178 if ( tempchar == 'M')
1180 *hf = &hf_mgcp_param_restartmethod;
1183 if (tempchar == 'D')
1185 *hf = &hf_mgcp_param_restartdelay;
1189 *hf = &hf_mgcp_param_signalreq;
1190 buf = &(mi->signalReq);
1193 *hf = &hf_mgcp_param_digitmap;
1194 mi->hasDigitMap = TRUE;
1197 *hf = &hf_mgcp_param_observedevent;
1198 buf = &(mi->observedEvents);
1201 tvb_current_offset++;
1202 if (len > (tvb_current_offset - offset) &&
1203 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1205 *hf = &hf_mgcp_param_connectionparam;
1206 tvb_current_offset--;
1209 if ( tempchar == 'L')
1211 *hf = &hf_mgcp_param_packagelist;
1215 tvb_current_offset++;
1216 if (len > (tvb_current_offset - offset) &&
1217 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1219 *hf = &hf_mgcp_param_reasoncode;
1220 tvb_current_offset--;
1223 if ( tempchar == 'S')
1225 *hf = &hf_mgcp_param_eventstates;
1229 tvb_current_offset++;
1230 if (len > (tvb_current_offset - offset) &&
1231 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1233 *hf = &hf_mgcp_param_specificendpoint;
1234 tvb_current_offset--;
1237 if (tempchar == '2')
1239 *hf = &hf_mgcp_param_secondendpointid;
1243 *hf = &hf_mgcp_param_reqinfo;
1246 *hf = &hf_mgcp_param_quarantinehandling;
1249 *hf = &hf_mgcp_param_detectedevents;
1252 *hf = &hf_mgcp_param_capabilities;
1256 *hf = &hf_mgcp_param_invalid;
1260 /* Move to (hopefully) the colon */
1261 tvb_current_offset++;
1263 /* Add a recognised parameter type if we have one */
1264 if (*hf != NULL && len > (tvb_current_offset - offset) &&
1265 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1267 tvb_current_offset++;
1268 tvb_current_offset = tvb_skip_wsp(tvb,tvb_current_offset, (len - tvb_current_offset + offset));
1269 returnvalue = tvb_current_offset;
1271 /* set the observedEvents or signalReq used in Voip Calls analysis */
1273 *buf = tvb_get_string(tvb, tvb_current_offset, (len - tvb_current_offset + offset));
1279 /* Was an empty line */
1280 *hf = &hf_mgcp_param_invalid;
1283 /* For these types, show the whole line */
1284 if ((*hf == &hf_mgcp_param_invalid) ||
1285 (*hf == &hf_mgcp_param_extension) || (*hf == &hf_mgcp_param_extension_critical))
1287 returnvalue = offset;
1295 * dissect_mgcp_firstline - Dissects the firstline of an MGCP message.
1296 * Adds the appropriate headers fields to
1297 * tree for the dissection of the first line
1298 * of an MGCP message.
1301 * tvb - The tvb containing the first line of an MGCP message. This
1302 * tvb is presumed to ONLY contain the first line of the MGCP
1304 * pinfo - The packet info for the packet. This is not really used
1305 * by this function but is passed through so as to retain the
1306 * style of a dissector.
1307 * tree - The tree from which to hang the structured information parsed
1308 * from the first line of the MGCP message.
1310 static void dissect_mgcp_firstline(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1312 gint tvb_current_offset,tvb_previous_offset,tvb_len,tvb_current_len;
1313 gint tokennum, tokenlen;
1314 char *transid = NULL;
1316 char *endpointId = NULL;
1317 mgcp_type_t mgcp_type = MGCP_OTHERS;
1318 conversation_t* conversation;
1319 mgcp_call_info_key mgcp_call_key;
1320 mgcp_call_info_key *new_mgcp_call_key = NULL;
1321 mgcp_call_t *mgcp_call = NULL;
1324 const gchar *verb_description = "";
1325 char code_with_verb[64] = ""; /* To fit "<4-letter-code> (<longest-verb>)" */
1327 static address null_address = { AT_NONE, 0, NULL };
1328 tvb_previous_offset = 0;
1329 tvb_len = tvb_length(tvb);
1330 tvb_current_len = tvb_len;
1331 tvb_current_offset = tvb_previous_offset;
1332 mi->is_duplicate = FALSE;
1333 mi->request_available = FALSE;
1341 tvb_current_len = tvb_length_remaining(tvb,tvb_previous_offset);
1342 tvb_current_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_current_len, ' ');
1343 if (tvb_current_offset == -1)
1345 tvb_current_offset = tvb_len;
1346 tokenlen = tvb_current_len;
1350 tokenlen = tvb_current_offset - tvb_previous_offset;
1355 THROW(ReportedBoundsError);
1356 code = tvb_format_text(tvb,tvb_previous_offset,tokenlen);
1357 strncpy(mi->code,code,4);
1359 if (is_mgcp_verb(tvb,tvb_previous_offset,tvb_current_len,&verb_description))
1361 mgcp_type = MGCP_REQUEST;
1362 if (verb_description != NULL)
1364 /* Can show verb along with code if known */
1365 sprintf(code_with_verb, "%s (%s)", code, verb_description);
1368 proto_tree_add_string_format(tree, hf_mgcp_req_verb, tvb,
1369 tvb_previous_offset, tokenlen,
1371 strlen(code_with_verb) ? code_with_verb : code);
1374 if (is_mgcp_rspcode(tvb,tvb_previous_offset,tvb_current_len))
1376 mgcp_type = MGCP_RESPONSE;
1377 rspcode = atoi(code);
1378 mi->rspcode = rspcode;
1379 proto_tree_add_uint(tree,hf_mgcp_rsp_rspcode, tvb,
1380 tvb_previous_offset, tokenlen, rspcode);
1389 transid = tvb_format_text(tvb,tvb_previous_offset,tokenlen);
1390 /* XXX - what if this isn't a valid text string? */
1391 mi->transid = atol(transid);
1392 proto_tree_add_string(tree, hf_mgcp_transid, tvb,
1393 tvb_previous_offset, tokenlen, transid);
1397 if (mgcp_type == MGCP_REQUEST)
1399 endpointId = tvb_format_text(tvb, tvb_previous_offset,tokenlen);
1400 mi->endpointId = g_strdup(endpointId);
1401 proto_tree_add_string(tree,hf_mgcp_req_endpoint, tvb,
1402 tvb_previous_offset, tokenlen, endpointId);
1405 if (mgcp_type == MGCP_RESPONSE)
1407 if (tvb_current_offset < tvb_len)
1409 tokenlen = tvb_find_line_end(tvb, tvb_previous_offset,
1410 -1, &tvb_current_offset, FALSE);
1414 tokenlen = tvb_current_len;
1416 proto_tree_add_string(tree, hf_mgcp_rsp_rspstring, tvb,
1417 tvb_previous_offset, tokenlen,
1418 tvb_format_text(tvb, tvb_previous_offset,
1424 if ((tokennum == 3 && mgcp_type == MGCP_REQUEST))
1426 if (tvb_current_offset < tvb_len )
1428 tokenlen = tvb_find_line_end(tvb, tvb_previous_offset,
1429 -1, &tvb_current_offset,FALSE);
1433 tokenlen = tvb_current_len;
1435 proto_tree_add_string(tree,hf_mgcp_version, tvb,
1436 tvb_previous_offset, tokenlen,
1437 tvb_format_text(tvb,tvb_previous_offset,
1441 if (tvb_current_offset < tvb_len)
1443 tvb_previous_offset = tvb_skip_wsp(tvb, tvb_current_offset,
1447 } while (tvb_current_offset < tvb_len && tvb_previous_offset < tvb_len && tokennum <= 3);
1452 proto_tree_add_boolean_hidden(tree, hf_mgcp_rsp, tvb, 0, 0, TRUE);
1453 /* Check for MGCP response. A response must match a call that
1454 we've seen, and the response must be sent to the same
1455 port and address that the call came from, and must
1456 come from the port to which the call was sent.
1458 If the transport is connection-oriented (we check, for
1459 now, only for "pinfo->ptype" of PT_TCP), we take
1460 into account the address from which the call was sent
1461 and the address to which the call was sent, because
1462 the addresses of the two endpoints should be the same
1463 for all calls and replies.
1465 If the transport is connectionless, we don't worry
1466 about the address to which the call was sent and from
1467 which the reply was sent, because there's no
1468 guarantee that the reply will come from the address
1469 to which the call was sent. */
1470 if (pinfo->ptype == PT_TCP)
1472 conversation = find_conversation(pinfo->fd->num, &pinfo->src,
1473 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1474 pinfo->destport, 0);
1478 /* XXX - can we just use NO_ADDR_B? Unfortunately,
1479 * you currently still have to pass a non-null
1480 * pointer for the second address argument even
1483 conversation = find_conversation(pinfo->fd->num, &null_address,
1484 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1485 pinfo->destport, 0);
1487 if (conversation != NULL)
1489 /* Look only for matching request, if
1490 matching conversation is available. */
1491 mgcp_call_key.transid = mi->transid;
1492 mgcp_call_key.conversation = conversation;
1493 mgcp_call = g_hash_table_lookup(mgcp_calls, &mgcp_call_key);
1496 /* Indicate the frame to which this is a reply. */
1497 if (mgcp_call->req_num)
1500 mi->request_available = TRUE;
1501 mgcp_call->responded = TRUE;
1502 mi->req_num = mgcp_call->req_num;
1503 strcpy(mi->code,mgcp_call->code);
1504 item = proto_tree_add_uint_format(tree, hf_mgcp_req_frame,
1505 tvb, 0, 0, mgcp_call->req_num,
1506 "This is a response to a request in frame %u",
1507 mgcp_call->req_num);
1508 PROTO_ITEM_SET_GENERATED(item);
1509 delta.secs= pinfo->fd->abs_secs-mgcp_call->req_time.secs;
1510 delta.nsecs=pinfo->fd->abs_usecs*1000-mgcp_call->req_time.nsecs;
1513 delta.nsecs+=1000000000;
1516 item = proto_tree_add_time(tree, hf_mgcp_time, tvb, 0, 0, &delta);
1517 PROTO_ITEM_SET_GENERATED(item);
1520 if (mgcp_call->rsp_num == 0)
1522 /* We have not yet seen a response to that call, so
1523 this must be the first response; remember its
1525 mgcp_call->rsp_num = pinfo->fd->num;
1529 /* We have seen a response to this call - but was it
1530 *this* response? (disregard provisional responses) */
1531 if ((mgcp_call->rsp_num != pinfo->fd->num) &&
1532 (mi->rspcode >= 200) &&
1533 (mi->rspcode == mgcp_call->rspcode))
1535 /* No, so it's a duplicate response. Mark it as such. */
1536 mi->is_duplicate = TRUE;
1537 if (check_col(pinfo->cinfo, COL_INFO))
1539 col_append_fstr(pinfo->cinfo, COL_INFO,
1540 ", Duplicate Response %u",
1546 proto_tree_add_uint_hidden(tree, hf_mgcp_dup, tvb, 0,0, mi->transid);
1547 item = proto_tree_add_uint(tree, hf_mgcp_rsp_dup,
1548 tvb, 0, 0, mi->transid);
1549 PROTO_ITEM_SET_GENERATED(item);
1553 /* Now store the response code (after comparison above) */
1554 mgcp_call->rspcode = mi->rspcode;
1559 proto_tree_add_boolean_hidden(tree, hf_mgcp_req, tvb, 0, 0, TRUE);
1560 /* Keep track of the address and port whence the call came,
1561 * and the port to which the call is being sent, so that
1562 * we can match up calls with replies.
1564 * If the transport is connection-oriented (we check, for
1565 * now, only for "pinfo->ptype" of PT_TCP), we take
1566 * into account the address from which the call was sent
1567 * and the address to which the call was sent, because
1568 * the addresses of the two endpoints should be the same
1569 * for all calls and replies.
1571 * If the transport is connectionless, we don't worry
1572 * about the address to which the call was sent and from
1573 * which the reply was sent, because there's no
1574 * guarantee that the reply will come from the address
1575 * to which the call was sent.
1577 if (pinfo->ptype == PT_TCP)
1579 conversation = find_conversation(pinfo->fd->num, &pinfo->src,
1580 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1581 pinfo->destport, 0);
1586 * XXX - can we just use NO_ADDR_B? Unfortunately,
1587 * you currently still have to pass a non-null
1588 * pointer for the second address argument even
1591 conversation = find_conversation(pinfo->fd->num, &pinfo->src,
1592 &null_address, pinfo->ptype, pinfo->srcport,
1593 pinfo->destport, 0);
1595 if (conversation == NULL)
1597 /* It's not part of any conversation - create a new one. */
1598 if (pinfo->ptype == PT_TCP)
1600 conversation = conversation_new(pinfo->fd->num, &pinfo->src,
1601 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1602 pinfo->destport, 0);
1606 conversation = conversation_new(pinfo->fd->num, &pinfo->src,
1607 &null_address, pinfo->ptype, pinfo->srcport,
1608 pinfo->destport, 0);
1612 /* Prepare the key data */
1613 mgcp_call_key.transid = mi->transid;
1614 mgcp_call_key.conversation = conversation;
1616 /* Look up the request */
1617 mgcp_call = g_hash_table_lookup(mgcp_calls, &mgcp_call_key);
1618 if (mgcp_call != NULL)
1620 /* We've seen a request with this TRANSID, with the same
1621 source and destination, before - but was it
1623 if (pinfo->fd->num != mgcp_call->req_num)
1625 /* No, so it's a duplicate request. Mark it as such. */
1626 mi->is_duplicate = TRUE;
1627 mi->req_num = mgcp_call->req_num;
1628 if (check_col(pinfo->cinfo, COL_INFO))
1630 col_append_fstr(pinfo->cinfo, COL_INFO,
1631 ", Duplicate Request %u",
1637 proto_tree_add_uint_hidden(tree, hf_mgcp_dup, tvb, 0,0, mi->transid);
1638 item = proto_tree_add_uint(tree, hf_mgcp_req_dup, tvb, 0,0, mi->transid);
1639 PROTO_ITEM_SET_GENERATED(item);
1645 /* Prepare the value data.
1646 "req_num" and "rsp_num" are frame numbers;
1647 frame numbers are 1-origin, so we use 0
1648 to mean "we don't yet know in which frame
1649 the reply for this call appears". */
1650 new_mgcp_call_key = g_mem_chunk_alloc(mgcp_call_info_key_chunk);
1651 *new_mgcp_call_key = mgcp_call_key;
1652 mgcp_call = g_mem_chunk_alloc(mgcp_call_info_value_chunk);
1653 mgcp_call->req_num = pinfo->fd->num;
1654 mgcp_call->rsp_num = 0;
1655 mgcp_call->transid = mi->transid;
1656 mgcp_call->responded = FALSE;
1657 mgcp_call->req_time.secs=pinfo->fd->abs_secs;
1658 mgcp_call->req_time.nsecs=pinfo->fd->abs_usecs*1000;
1659 strcpy(mgcp_call->code,mi->code);
1662 g_hash_table_insert(mgcp_calls, new_mgcp_call_key, mgcp_call);
1664 if (mgcp_call && mgcp_call->rsp_num)
1666 proto_item* item = proto_tree_add_uint_format(tree, hf_mgcp_rsp_frame,
1667 tvb, 0, 0, mgcp_call->rsp_num,
1668 "The response to this request is in frame %u",
1669 mgcp_call->rsp_num);
1670 PROTO_ITEM_SET_GENERATED(item);
1677 mi->mgcp_type = mgcp_type;
1680 mi->req_time.secs=mgcp_call->req_time.secs;
1681 mi->req_time.nsecs=mgcp_call->req_time.nsecs;
1685 tap_queue_packet(mgcp_tap, pinfo, mi);
1689 * dissect_mgcp_params - Dissects the parameters of an MGCP message.
1690 * Adds the appropriate headers fields to
1691 * tree for the dissection of the parameters
1692 * of an MGCP message.
1695 * tvb - The tvb containing the parameters of an MGCP message. This
1696 * tvb is presumed to ONLY contain the part of the MGCP
1697 * message which contains the MGCP parameters.
1698 * tree - The tree from which to hang the structured information parsed
1699 * from the parameters of the MGCP message.
1701 static void dissect_mgcp_params(tvbuff_t *tvb, proto_tree *tree)
1703 int linelen, tokenlen, *my_param;
1704 gint tvb_lineend,tvb_current_len, tvb_linebegin,tvb_len,old_lineend;
1705 gint tvb_tokenbegin;
1706 proto_tree *mgcp_param_ti, *mgcp_param_tree;
1708 tvb_len = tvb_length(tvb);
1710 tvb_current_len = tvb_length_remaining(tvb,tvb_linebegin);
1711 tvb_lineend = tvb_linebegin;
1715 mgcp_param_ti = proto_tree_add_item(tree, hf_mgcp_params, tvb,
1716 tvb_linebegin, tvb_len, FALSE);
1717 proto_item_set_text(mgcp_param_ti, "Parameters");
1718 mgcp_param_tree = proto_item_add_subtree(mgcp_param_ti, ett_mgcp_param);
1720 /* Parse the parameters */
1721 while (tvb_lineend < tvb_len)
1723 old_lineend = tvb_lineend;
1724 linelen = tvb_find_line_end(tvb, tvb_linebegin, -1,&tvb_lineend,FALSE);
1725 tvb_tokenbegin = tvb_parse_param(tvb, tvb_linebegin, linelen, &my_param);
1729 if (*my_param == hf_mgcp_param_connectionparam)
1731 tokenlen = tvb_find_line_end(tvb,tvb_tokenbegin,-1,&tvb_lineend,FALSE);
1732 dissect_mgcp_connectionparams(mgcp_param_tree, tvb, tvb_linebegin,
1733 tvb_tokenbegin - tvb_linebegin, tokenlen);
1736 if (*my_param == hf_mgcp_param_localconnoptions)
1738 tokenlen = tvb_find_line_end(tvb,tvb_tokenbegin,-1,&tvb_lineend,FALSE);
1739 dissect_mgcp_localconnectionoptions(mgcp_param_tree, tvb, tvb_linebegin,
1740 tvb_tokenbegin - tvb_linebegin, tokenlen);
1744 tokenlen = tvb_find_line_end(tvb,tvb_tokenbegin,-1,&tvb_lineend,FALSE);
1745 proto_tree_add_string(mgcp_param_tree,*my_param, tvb,
1746 tvb_linebegin, linelen,
1747 tvb_format_text(tvb,tvb_tokenbegin, tokenlen));
1751 tvb_linebegin = tvb_lineend;
1752 /* Its a infinite loop if we didn't advance (or went backwards) */
1753 if (old_lineend >= tvb_lineend)
1755 THROW(ReportedBoundsError);
1761 /* Dissect the connection params */
1763 dissect_mgcp_connectionparams(proto_tree *parent_tree, tvbuff_t *tvb, gint offset, gint param_type_len, gint param_val_len)
1765 proto_tree *tree = parent_tree;
1766 proto_item *item = NULL;
1768 gchar *tokenline = NULL;
1769 gchar **tokens = NULL;
1770 gchar **typval = NULL;
1778 item = proto_tree_add_item(parent_tree, hf_mgcp_param_connectionparam, tvb, offset, param_type_len+param_val_len, FALSE);
1779 tree = proto_item_add_subtree(item, ett_mgcp_param_connectionparam);
1783 offset += param_type_len; /* skip the P: */
1784 tokenline = tvb_get_string(tvb, offset, param_val_len);
1786 /* Split into type=value pairs separated by comma */
1787 tokens = g_strsplit(tokenline, ",", -1);
1788 for (i = 0; tokens[i] != NULL; i++)
1790 tokenlen = strlen(tokens[i]);
1791 typval = g_strsplit(tokens[i], "=", 2);
1792 if ((typval[0] != NULL) && (typval[1] != NULL))
1794 if (!strcasecmp(g_strstrip(typval[0]), "PS"))
1796 hf_uint = hf_mgcp_param_connectionparam_ps;
1798 else if (!strcasecmp(g_strstrip(typval[0]), "OS"))
1800 hf_uint = hf_mgcp_param_connectionparam_os;
1802 else if (!strcasecmp(g_strstrip(typval[0]), "PR"))
1804 hf_uint = hf_mgcp_param_connectionparam_pr;
1806 else if (!strcasecmp(g_strstrip(typval[0]), "OR"))
1808 hf_uint = hf_mgcp_param_connectionparam_or;
1810 else if (!strcasecmp(g_strstrip(typval[0]), "PL"))
1812 hf_uint = hf_mgcp_param_connectionparam_pl;
1814 else if (!strcasecmp(g_strstrip(typval[0]), "JI"))
1816 hf_uint = hf_mgcp_param_connectionparam_ji;
1818 else if (!strcasecmp(g_strstrip(typval[0]), "LA"))
1820 hf_uint = hf_mgcp_param_connectionparam_la;
1822 else if (!strcasecmp(g_strstrip(typval[0]), "PC/RPS"))
1824 hf_uint = hf_mgcp_param_connectionparam_pcrps;
1825 } else if (!strcasecmp(g_strstrip(typval[0]), "PC/ROS"))
1827 hf_uint = hf_mgcp_param_connectionparam_pcros;
1829 else if (!strcasecmp(g_strstrip(typval[0]), "PC/RPL"))
1831 hf_uint = hf_mgcp_param_connectionparam_pcrpl;
1833 else if (!strcasecmp(g_strstrip(typval[0]), "PC/RJI"))
1835 hf_uint = hf_mgcp_param_connectionparam_pcrji;
1837 else if (!strncasecmp(g_strstrip(typval[0]), "X-", 2))
1839 hf_string = hf_mgcp_param_connectionparam_x;
1851 proto_tree_add_uint(tree, hf_uint, tvb, offset, tokenlen, atol(typval[1]));
1853 else if (hf_string != -1)
1855 proto_tree_add_string(tree, hf_string, tvb, offset, tokenlen, g_strstrip(typval[1]));
1859 proto_tree_add_text(tree, tvb, offset, tokenlen, "Unknown parameter: %s", tokens[i]);
1865 proto_tree_add_text(tree, tvb, offset, tokenlen, "Malformed parameter: %s", tokens[i]);
1867 offset += tokenlen + 1; /* 1 extra for the delimiter */
1875 /* Dissect the local connection option */
1877 dissect_mgcp_localconnectionoptions(proto_tree *parent_tree, tvbuff_t *tvb, gint offset, gint param_type_len, gint param_val_len)
1879 proto_tree *tree = parent_tree;
1880 proto_item *item = NULL;
1882 gchar *tokenline = NULL;
1883 gchar **tokens = NULL;
1884 gchar **typval = NULL;
1892 item = proto_tree_add_item(parent_tree, hf_mgcp_param_localconnoptions, tvb, offset, param_type_len+param_val_len, FALSE);
1893 tree = proto_item_add_subtree(item, ett_mgcp_param_localconnectionoptions);
1897 offset += param_type_len; /* skip the L: */
1898 tokenline = tvb_get_string(tvb, offset, param_val_len);
1900 /* Split into type=value pairs separated by comma */
1901 tokens = g_strsplit(tokenline, ",", -1);
1902 for (i = 0; tokens[i] != NULL; i++)
1907 tokenlen = strlen(tokens[i]);
1908 typval = g_strsplit(tokens[i], ":", 2);
1909 if ((typval[0] != NULL) && (typval[1] != NULL))
1911 if (!strcasecmp(g_strstrip(typval[0]), "p"))
1913 hf_uint = hf_mgcp_param_localconnoptions_p;
1915 else if (!strcasecmp(g_strstrip(typval[0]), "a"))
1917 hf_string = hf_mgcp_param_localconnoptions_a;
1919 else if (!strcasecmp(g_strstrip(typval[0]), "s"))
1921 hf_string = hf_mgcp_param_localconnoptions_s;
1923 else if (!strcasecmp(g_strstrip(typval[0]), "e"))
1925 hf_string = hf_mgcp_param_localconnoptions_e;
1927 else if (!strcasecmp(g_strstrip(typval[0]), "sc-rtp"))
1929 hf_string = hf_mgcp_param_localconnoptions_scrtp;
1931 else if (!strcasecmp(g_strstrip(typval[0]), "sc-rtcp"))
1933 hf_string = hf_mgcp_param_localconnoptions_scrtcp;
1935 else if (!strcasecmp(g_strstrip(typval[0]), "b"))
1937 hf_string = hf_mgcp_param_localconnoptions_b;
1939 else if (!strcasecmp(g_strstrip(typval[0]), "es-ccd"))
1941 hf_string = hf_mgcp_param_localconnoptions_esccd;
1943 else if (!strcasecmp(g_strstrip(typval[0]), "es-cci"))
1945 hf_string = hf_mgcp_param_localconnoptions_escci;
1947 else if (!strcasecmp(g_strstrip(typval[0]), "dq-gi"))
1949 hf_string = hf_mgcp_param_localconnoptions_dqgi;
1951 else if (!strcasecmp(g_strstrip(typval[0]), "dq-rd"))
1953 hf_string = hf_mgcp_param_localconnoptions_dqrd;
1955 else if (!strcasecmp(g_strstrip(typval[0]), "dq-ri"))
1957 hf_string = hf_mgcp_param_localconnoptions_dqri;
1959 else if (!strcasecmp(g_strstrip(typval[0]), "dq-rr"))
1961 hf_string = hf_mgcp_param_localconnoptions_dqrr;
1963 else if (!strcasecmp(g_strstrip(typval[0]), "k"))
1965 hf_string = hf_mgcp_param_localconnoptions_k;
1967 else if (!strcasecmp(g_strstrip(typval[0]), "gc"))
1969 hf_uint = hf_mgcp_param_localconnoptions_gc;
1971 else if (!strcasecmp(g_strstrip(typval[0]), "fmtp"))
1973 hf_string = hf_mgcp_param_localconnoptions_fmtp;
1975 else if (!strcasecmp(g_strstrip(typval[0]), "nt"))
1977 hf_string = hf_mgcp_param_localconnoptions_nt;
1979 else if (!strcasecmp(g_strstrip(typval[0]), "o-fmtp"))
1981 hf_string = hf_mgcp_param_localconnoptions_ofmtp;
1983 else if (!strcasecmp(g_strstrip(typval[0]), "r"))
1985 hf_string = hf_mgcp_param_localconnoptions_r;
1987 else if (!strcasecmp(g_strstrip(typval[0]), "t"))
1989 hf_string = hf_mgcp_param_localconnoptions_t;
1991 else if (!strcasecmp(g_strstrip(typval[0]), "r-cnf"))
1993 hf_string = hf_mgcp_param_localconnoptions_rcnf;
1995 else if (!strcasecmp(g_strstrip(typval[0]), "r-dir"))
1997 hf_string = hf_mgcp_param_localconnoptions_rdir;
1999 else if (!strcasecmp(g_strstrip(typval[0]), "r-sh"))
2001 hf_string = hf_mgcp_param_localconnoptions_rsh;
2014 proto_tree_add_uint(tree, hf_uint, tvb, offset, tokenlen, atol(typval[1]));
2016 else if (hf_string != -1)
2018 proto_tree_add_string(tree, hf_string, tvb, offset, tokenlen, g_strstrip(typval[1]));
2022 proto_tree_add_text(tree, tvb, offset, tokenlen, "Unknown parameter: %s", tokens[i]);
2028 proto_tree_add_text(tree, tvb, offset, tokenlen, "Malformed parameter: %s", tokens[i]);
2030 offset += tokenlen + 1; /* 1 extra for the delimiter */
2041 * tvb_skip_wsp - Returns the position in tvb of the first non-whitespace
2042 * character following offset or offset + maxlength -1 whichever
2046 * tvb - The tvbuff in which we are skipping whitespace.
2047 * offset - The offset in tvb from which we begin trying to skip whitespace.
2048 * maxlength - The maximum distance from offset that we may try to skip
2051 * Returns: The position in tvb of the first non-whitespace
2052 * character following offset or offset + maxlength -1 whichever
2055 static gint tvb_skip_wsp(tvbuff_t* tvb, gint offset, gint maxlength)
2057 gint counter = offset;
2058 gint end = offset + maxlength,tvb_len;
2061 /* Get the length remaining */
2062 tvb_len = tvb_length(tvb);
2063 end = offset + maxlength;
2069 /* Skip past spaces and tabs until run out or meet something else */
2070 for (counter = offset;
2072 ((tempchar = tvb_get_guint8(tvb,counter)) == ' ' ||
2080 * tvb_find_null_line - Returns the length from offset to the first null
2081 * line found (a null line is a line that begins
2082 * with a CR or LF. The offset to the first character
2083 * after the null line is written into the gint pointed
2084 * to by next_offset.
2087 * tvb - The tvbuff in which we are looking for a null line.
2088 * offset - The offset in tvb at which we will begin looking for
2090 * len - The maximum distance from offset in tvb that we will look for
2091 * a null line. If it is -1 we will look to the end of the buffer.
2093 * next_offset - The location to write the offset of first character
2094 * FOLLOWING the null line.
2096 * Returns: The length from offset to the first character BEFORE
2099 static gint tvb_find_null_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset)
2101 gint tvb_lineend,tvb_current_len,tvb_linebegin,maxoffset;
2104 tvb_linebegin = offset;
2105 tvb_lineend = tvb_linebegin;
2107 /* Simple setup to allow for the traditional -1 search to the end of the tvbuff */
2110 tvb_current_len = len;
2114 tvb_current_len = tvb_length_remaining(tvb,offset);
2117 maxoffset = (tvb_current_len - 1) + offset;
2119 /* Loop around until we either find a line begining with a carriage return
2120 or newline character or until we hit the end of the tvbuff. */
2123 tvb_linebegin = tvb_lineend;
2124 tvb_current_len = tvb_length_remaining(tvb,tvb_linebegin);
2125 tvb_find_line_end(tvb, tvb_linebegin, tvb_current_len, &tvb_lineend,FALSE);
2126 tempchar = tvb_get_guint8(tvb,tvb_linebegin);
2127 } while (tempchar != '\r' && tempchar != '\n' && tvb_lineend <= maxoffset);
2130 *next_offset = tvb_lineend;
2132 if (tvb_lineend <= maxoffset)
2134 tvb_current_len = tvb_linebegin - offset;
2138 tvb_current_len = tvb_length_remaining(tvb,offset);
2141 return tvb_current_len;
2145 * tvb_find_dot_line - Returns the length from offset to the first line
2146 * containing only a dot (.) character. A line
2147 * containing only a dot is used to indicate a
2148 * separation between multiple MGCP messages
2149 * piggybacked in the same UDP packet.
2152 * tvb - The tvbuff in which we are looking for a dot line.
2153 * offset - The offset in tvb at which we will begin looking for
2155 * len - The maximum distance from offset in tvb that we will look for
2156 * a dot line. If it is -1 we will look to the end of the buffer.
2158 * next_offset - The location to write the offset of first character
2159 * FOLLOWING the dot line.
2161 * Returns: The length from offset to the first character BEFORE
2162 * the dot line or -1 if the character at offset is a .
2163 * followed by a newline or a carriage return.
2165 static gint tvb_find_dot_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset)
2167 gint tvb_current_offset, tvb_current_len, maxoffset,tvb_len;
2169 tvb_current_offset = offset;
2170 tvb_current_len = len;
2171 tvb_len = tvb_length(tvb);
2175 maxoffset = tvb_len - 1;
2179 maxoffset = (len - 1) + offset;
2181 tvb_current_offset = offset -1;
2185 tvb_current_offset = tvb_find_guint8(tvb, tvb_current_offset+1,
2186 tvb_current_len, '.');
2187 tvb_current_len = maxoffset - tvb_current_offset + 1;
2189 /* If we didn't find a . then break out of the loop */
2190 if (tvb_current_offset == -1)
2195 /* Do we have and characters following the . ? */
2196 if (tvb_current_offset < maxoffset)
2198 tempchar = tvb_get_guint8(tvb,tvb_current_offset+1);
2199 /* Are the characters that follow the dot a newline or carriage return ? */
2200 if (tempchar == '\r' || tempchar == '\n')
2202 /* Do we have any charaters that proceed the . ? */
2203 if (tvb_current_offset == 0)
2209 tempchar = tvb_get_guint8(tvb,tvb_current_offset-1);
2211 /* Are the characters that follow the dot a newline or a
2212 carriage return ? */
2213 if (tempchar == '\r' || tempchar == '\n')
2221 if (tvb_current_offset == maxoffset)
2223 if (tvb_current_offset == 0)
2229 tempchar = tvb_get_guint8(tvb,tvb_current_offset-1);
2230 if (tempchar == '\r' || tempchar == '\n')
2236 } while (tvb_current_offset < maxoffset);
2240 * So now we either have the tvb_current_offset of a . in a dot line
2241 * or a tvb_current_offset of -1
2243 if (tvb_current_offset == -1)
2245 tvb_current_offset = maxoffset +1;
2246 *next_offset = maxoffset + 1;
2250 tvb_find_line_end(tvb,tvb_current_offset,tvb_current_len,next_offset,FALSE);
2253 if (tvb_current_offset == offset)
2255 tvb_current_len = -1;
2259 tvb_current_len = tvb_current_offset - offset;
2262 return tvb_current_len;
2265 /* Start the functions we need for the plugin stuff */
2267 #ifndef ENABLE_STATIC
2269 G_MODULE_EXPORT void
2270 plugin_register(void)
2272 /* Register the new protocol, protocol fields, and subtrees */
2273 if (proto_mgcp == -1)
2275 /* Execute protocol initialization only once */
2276 proto_register_mgcp();
2280 G_MODULE_EXPORT void
2281 plugin_reg_handoff(void)
2283 proto_reg_handoff_mgcp();
2288 /* End the functions we need for plugin stuff */