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 * Wireshark - Network traffic analyzer
18 * By Gerald Combs <gerald@wireshark.org>
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.
42 #include <epan/packet.h>
43 #include <epan/emem.h>
44 #include <epan/proto.h>
45 #include <epan/prefs.h>
46 #include <epan/conversation.h>
48 #include "packet-mgcp.h"
50 #define TCP_PORT_MGCP_GATEWAY 2427
51 #define UDP_PORT_MGCP_GATEWAY 2427
52 #define TCP_PORT_MGCP_CALLAGENT 2727
53 #define UDP_PORT_MGCP_CALLAGENT 2727
56 /* Define the mgcp proto */
57 static int proto_mgcp = -1;
59 /* Define many many headers for mgcp */
60 static int hf_mgcp_req = -1;
61 static int hf_mgcp_req_verb = -1;
62 static int hf_mgcp_req_endpoint = -1;
63 static int hf_mgcp_req_frame = -1;
64 static int hf_mgcp_rsp = -1;
65 static int hf_mgcp_rsp_frame = -1;
66 static int hf_mgcp_time = -1;
67 static int hf_mgcp_transid = -1;
68 static int hf_mgcp_version = -1;
69 static int hf_mgcp_rsp_rspcode = -1;
70 static int hf_mgcp_rsp_rspstring = -1;
71 static int hf_mgcp_params = -1;
72 static int hf_mgcp_param_rspack = -1;
73 static int hf_mgcp_param_bearerinfo = -1;
74 static int hf_mgcp_param_callid = -1;
75 static int hf_mgcp_param_connectionid = -1;
76 static int hf_mgcp_param_secondconnectionid = -1;
77 static int hf_mgcp_param_notifiedentity = -1;
78 static int hf_mgcp_param_requestid = -1;
79 static int hf_mgcp_param_localconnoptions = -1;
80 static int hf_mgcp_param_localconnoptions_p = -1;
81 static int hf_mgcp_param_localconnoptions_a = -1;
82 static int hf_mgcp_param_localconnoptions_s = -1;
83 static int hf_mgcp_param_localconnoptions_e = -1;
84 static int hf_mgcp_param_localconnoptions_scrtp = -1;
85 static int hf_mgcp_param_localconnoptions_scrtcp = -1;
86 static int hf_mgcp_param_localconnoptions_b = -1;
87 static int hf_mgcp_param_localconnoptions_esccd = -1;
88 static int hf_mgcp_param_localconnoptions_escci = -1;
89 static int hf_mgcp_param_localconnoptions_dqgi = -1;
90 static int hf_mgcp_param_localconnoptions_dqrd = -1;
91 static int hf_mgcp_param_localconnoptions_dqri = -1;
92 static int hf_mgcp_param_localconnoptions_dqrr = -1;
93 static int hf_mgcp_param_localconnoptions_k = -1;
94 static int hf_mgcp_param_localconnoptions_gc = -1;
95 static int hf_mgcp_param_localconnoptions_fmtp = -1;
96 static int hf_mgcp_param_localconnoptions_nt = -1;
97 static int hf_mgcp_param_localconnoptions_ofmtp = -1;
98 static int hf_mgcp_param_localconnoptions_r = -1;
99 static int hf_mgcp_param_localconnoptions_t = -1;
100 static int hf_mgcp_param_localconnoptions_rcnf = -1;
101 static int hf_mgcp_param_localconnoptions_rdir = -1;
102 static int hf_mgcp_param_localconnoptions_rsh = -1;
103 static int hf_mgcp_param_connectionmode = -1;
104 static int hf_mgcp_param_reqevents = -1;
105 static int hf_mgcp_param_restartmethod = -1;
106 static int hf_mgcp_param_restartdelay = -1;
107 static int hf_mgcp_param_signalreq = -1;
108 static int hf_mgcp_param_digitmap = -1;
109 static int hf_mgcp_param_observedevent = -1;
110 static int hf_mgcp_param_connectionparam = -1;
111 static int hf_mgcp_param_connectionparam_ps = -1;
112 static int hf_mgcp_param_connectionparam_os = -1;
113 static int hf_mgcp_param_connectionparam_pr = -1;
114 static int hf_mgcp_param_connectionparam_or = -1;
115 static int hf_mgcp_param_connectionparam_pl = -1;
116 static int hf_mgcp_param_connectionparam_ji = -1;
117 static int hf_mgcp_param_connectionparam_la = -1;
118 static int hf_mgcp_param_connectionparam_pcrps = -1;
119 static int hf_mgcp_param_connectionparam_pcros = -1;
120 static int hf_mgcp_param_connectionparam_pcrpl = -1;
121 static int hf_mgcp_param_connectionparam_pcrji = -1;
122 static int hf_mgcp_param_connectionparam_x = -1;
123 static int hf_mgcp_param_reasoncode = -1;
124 static int hf_mgcp_param_eventstates = -1;
125 static int hf_mgcp_param_specificendpoint = -1;
126 static int hf_mgcp_param_secondendpointid = -1;
127 static int hf_mgcp_param_reqinfo = -1;
128 static int hf_mgcp_param_quarantinehandling = -1;
129 static int hf_mgcp_param_detectedevents = -1;
130 static int hf_mgcp_param_capabilities = -1;
131 static int hf_mgcp_param_maxmgcpdatagram = -1;
132 static int hf_mgcp_param_packagelist = -1;
133 static int hf_mgcp_param_extension = -1;
134 static int hf_mgcp_param_extension_critical = -1;
135 static int hf_mgcp_param_invalid = -1;
136 static int hf_mgcp_messagecount = -1;
137 static int hf_mgcp_dup = -1;
138 static int hf_mgcp_req_dup = -1;
139 static int hf_mgcp_rsp_dup = -1;
141 static const value_string mgcp_return_code_vals[] = {
142 {000, "Response Acknowledgement"},
143 {100, "The transaction is currently being executed. An actual completion message will follow on later."},
144 {101, "The transaction has been queued for execution. An actual completion message will follow later."},
145 {200, "The requested transaction was executed normally."},
146 {250, "The connection was deleted."},
147 {400, "The transaction could not be executed, due to a transient error."},
148 {401, "The phone is already off hook"},
149 {402, "The phone is already on hook"},
150 {403, "The transaction could not be executed, because the endpoint does not have sufficient resources at this time"},
151 {404, "Insufficient bandwidth at this time"},
152 {405, "The transaction could not be executed, because the endpoint is \"restarting\"."},
153 {406, "Transaction time-out. The transaction did not complete in a reasonable period of time and has been aborted."},
154 {407, "Transaction aborted. The transaction was aborted by some external action, e.g., a ModifyConnection command aborted by a DeleteConnection command."},
155 {409, "The transaction could not be executed because of internal overload."},
156 {410, "No endpoint available. A valid \"any of\" wildcard was used, however there was no endpoint available to satisfy the request."},
157 {500, "The transaction could not be executed, because the endpoint is unknown."},
158 {501, "The transaction could not be executed, because the endpoint is not ready."},
159 {502, "The transaction could not be executed, because the endpoint does not have sufficient resources"},
160 {503, "\"All of\" wildcard too complicated."},
161 {504, "Unknown or unsupported command."},
162 {505, "Unsupported RemoteConnectionDescriptor."},
163 {506, "Unable to satisfy both LocalConnectionOptions and RemoteConnectionDescriptor."},
164 {507, "Unsupported functionality."},
165 {508, "Unknown or unsupported quarantine handling."},
166 {509, "Error in RemoteConnectionDescriptor."},
167 {510, "The transaction could not be executed, because a protocol error was detected."},
168 {511, "The transaction could not be executed, because the command contained an unrecognized extension."},
169 {512, "The transaction could not be executed, because the gateway is not equipped to detect one of the requested events."},
170 {513, "The transaction could not be executed, because the gateway is not equipped to generate one of the requested signals."},
171 {514, "The transaction could not be executed, because the gateway cannot send the specified announcement."},
172 {515, "The transaction refers to an incorrect connection-id (may have been already deleted)"},
173 {516, "The transaction refers to an unknown call-id."},
174 {517, "Unsupported or invalid mode."},
175 {518, "Unsupported or unknown package."},
176 {519, "Endpoint does not have a digit map."},
177 {520, "The transaction could not be executed, because the endpoint is 'restarting'."},
178 {521, "Endpoint redirected to another Call Agent."},
179 {522, "No such event or signal."},
180 {523, "Unknown action or illegal combination of actions"},
181 {524, "Internal inconsistency in LocalConnectionOptions"},
182 {525, "Unknown extension in LocalConnectionOptions"},
183 {526, "Insufficient bandwidth"},
184 {527, "Missing RemoteConnectionDescriptor"},
185 {528, "Incompatible protocol version"},
186 {529, "Internal hardware failure"},
187 {530, "CAS signaling protocol error."},
188 {531, "failure of a grouping of trunks (e.g. facility failure)."},
189 {532, "Unsupported value(s) in LocalConnectionOptions."},
190 {533, "Response too large."},
191 {534, "Codec negotiation failure."},
192 {535, "Packetization period not supported"},
193 {536, "Unknown or unsupported RestartMethod"},
194 {537, "Unknown or unsupported digit map extension"},
195 {538, "Event/signal parameter error (e.g., missing, erroneous, unsupported, unknown, etc.)"},
196 {539, "Invalid or unsupported command parameter."},
197 {540, "Per endpoint connection limit exceeded."},
198 {541, "Invalid or unsupported LocalConnectionOptions"},
202 /* TODO: add/use when tested/have capture to test with */
204 static const value_string mgcp_reason_code_vals[] = {
205 {0, "Endpoint state is normal"},
206 {900, "Endpoint malfunctioning."},
207 {901, "Endpoint taken out-of-service."},
208 {902, "Loss of lower layer connectivity (e.g., downstream sync)."},
209 {903, "QoS resource reservation was lost."},
210 {904, "Manual intervention."},
211 {905, "Facility failure (e.g., DS-0 failure)."},
218 * Define the trees for mgcp
219 * We need one for MGCP itself, one for the MGCP paramters and one
220 * for each of the dissected parameters
222 static int ett_mgcp = -1;
223 static int ett_mgcp_param = -1;
224 static int ett_mgcp_param_connectionparam = -1;
225 static int ett_mgcp_param_localconnectionoptions = -1;
228 * Define the tap for mgcp
230 static int mgcp_tap = -1;
233 * Here are the global variables associated with
234 * the various user definable characteristics of the dissection
236 * MGCP has two kinds of "agents", gateways and callagents. Callagents
237 * control gateways in a master/slave sort of arrangement. Since gateways
238 * and callagents have different well known ports and could both
239 * operate under either udp or tcp we have rather a lot of port info to
242 * global_mgcp_raw_text determines whether we are going to display
243 * the raw text of the mgcp message, much like the HTTP dissector does.
246 static int global_mgcp_gateway_tcp_port = TCP_PORT_MGCP_GATEWAY;
247 static int global_mgcp_gateway_udp_port = UDP_PORT_MGCP_GATEWAY;
248 static int global_mgcp_callagent_tcp_port = TCP_PORT_MGCP_CALLAGENT;
249 static int global_mgcp_callagent_udp_port = UDP_PORT_MGCP_CALLAGENT;
250 static gboolean global_mgcp_raw_text = FALSE;
251 static gboolean global_mgcp_message_count = FALSE;
254 * Variables to allow for proper deletion of dissector registration when
255 * the user changes port from the gui.
257 static int gateway_tcp_port = 0;
258 static int gateway_udp_port = 0;
259 static int callagent_tcp_port = 0;
260 static int callagent_udp_port = 0;
262 /* Some basic utility functions that are specific to this dissector */
263 static gboolean is_mgcp_verb(tvbuff_t *tvb, gint offset, gint maxlength, const gchar **verb_name);
264 static gboolean is_mgcp_rspcode(tvbuff_t *tvb, gint offset, gint maxlength);
265 static gint tvb_parse_param(tvbuff_t *tvb, gint offset, gint maxlength, int** hf);
268 * The various functions that either dissect some
269 * subpart of MGCP. These aren't really proto dissectors but they
270 * are written in the same style.
272 static void dissect_mgcp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
273 proto_tree *mgcp_tree, proto_tree *ti);
274 static void dissect_mgcp_firstline(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
275 static void dissect_mgcp_params(tvbuff_t *tvb, proto_tree *tree);
276 static void dissect_mgcp_connectionparams(proto_tree *parent_tree, tvbuff_t *tvb,
277 gint offset, gint param_type_len,
279 static void dissect_mgcp_localconnectionoptions(proto_tree *parent_tree, tvbuff_t *tvb,
280 gint offset, gint param_type_len,
283 static void mgcp_raw_text_add(tvbuff_t *tvb, proto_tree *tree);
286 * Some functions which should be moved to a library
287 * as I think that people may find them of general usefulness.
289 static gint tvb_skip_wsp(tvbuff_t* tvb, gint offset, gint maxlength);
290 static gint tvb_find_null_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset);
291 static gint tvb_find_dot_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset);
292 static gboolean is_rfc2234_alpha(guint8 c);
294 static dissector_handle_t sdp_handle;
298 * Init Hash table stuff
301 typedef struct _mgcp_call_info_key
304 conversation_t *conversation;
305 } mgcp_call_info_key;
307 static GMemChunk *mgcp_call_info_key_chunk;
308 static GMemChunk *mgcp_call_info_value_chunk;
309 static GHashTable *mgcp_calls;
312 static gint mgcp_call_equal(gconstpointer k1, gconstpointer k2)
314 const mgcp_call_info_key* key1 = (const mgcp_call_info_key*) k1;
315 const mgcp_call_info_key* key2 = (const mgcp_call_info_key*) k2;
317 return (key1->transid == key2->transid &&
318 key1->conversation == key2->conversation);
321 /* Calculate a hash key */
322 static guint mgcp_call_hash(gconstpointer k)
324 const mgcp_call_info_key* key = (const mgcp_call_info_key*) k;
326 return key->transid + key->conversation->index;
331 /************************************************************************
332 * dissect_mgcp - The dissector for the Media Gateway Control Protocol
333 ************************************************************************/
334 static void dissect_mgcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
337 guint32 num_messages;
338 gint tvb_sectionend,tvb_sectionbegin, tvb_len, tvb_current_len;
339 proto_tree *mgcp_tree, *ti;
340 const gchar *verb_name = "";
342 /* Initialize variables */
344 tvb_sectionbegin = tvb_sectionend;
346 tvb_len = tvb_length(tvb);
347 tvb_current_len = tvb_len;
353 * Set the columns now, so that they'll be set correctly if we throw
354 * an exception. We can set them later as well....
356 if (check_col(pinfo->cinfo, COL_PROTOCOL))
357 col_add_str(pinfo->cinfo, COL_PROTOCOL, "MGCP");
358 if (check_col(pinfo->cinfo, COL_INFO))
359 col_clear(pinfo->cinfo, COL_INFO);
362 * Check to see whether we're really dealing with MGCP by looking
363 * for a valid MGCP verb or response code. This isn't infallible,
364 * but its cheap and its better than nothing.
366 if (is_mgcp_verb(tvb,0,tvb_len, &verb_name) || is_mgcp_rspcode(tvb,0,tvb_len))
369 * Loop through however many mgcp messages may be stuck in
370 * this packet using piggybacking
377 /* Create our mgcp subtree */
378 ti = proto_tree_add_item(tree,proto_mgcp,tvb,0,0, FALSE);
379 mgcp_tree = proto_item_add_subtree(ti, ett_mgcp);
382 sectionlen = tvb_find_dot_line(tvb, tvb_sectionbegin, -1, &tvb_sectionend);
383 if (sectionlen != -1)
385 dissect_mgcp_message(tvb_new_subset(tvb, tvb_sectionbegin,
387 pinfo, tree, mgcp_tree,ti);
388 tvb_sectionbegin = tvb_sectionend;
394 } while (tvb_sectionend < tvb_len);
398 proto_tree_add_uint_hidden(mgcp_tree, hf_mgcp_messagecount, tvb,
399 0 ,0 , num_messages);
403 * Add our column information after dissecting SDP
404 * in order to prevent the column info changing to reflect the SDP
405 * (when showing message count)
407 tvb_sectionbegin = 0;
408 if (check_col(pinfo->cinfo, COL_PROTOCOL))
410 if (global_mgcp_message_count == TRUE )
412 if (num_messages > 1)
414 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "MGCP (%i messages)",num_messages);
418 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "MGCP (%i message)",num_messages);
423 if (check_col(pinfo->cinfo, COL_INFO))
425 sectionlen = tvb_find_line_end(tvb, tvb_sectionbegin,-1,
426 &tvb_sectionend,FALSE);
427 col_prepend_fstr(pinfo->cinfo, COL_INFO, "%s",
428 tvb_format_text(tvb, tvb_sectionbegin, sectionlen));
433 #define MAX_MGCP_MESSAGES_IN_PACKET 5
434 static mgcp_info_t pi_arr[MAX_MGCP_MESSAGES_IN_PACKET];
435 static int pi_current = 0;
436 static mgcp_info_t *mi;
438 /* Dissect an individual MGCP message */
439 static void dissect_mgcp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
440 proto_tree *mgcp_tree, proto_tree *ti)
442 /* Declare variables */
444 gint tvb_sectionend,tvb_sectionbegin, tvb_len, tvb_current_len;
446 const gchar *verb_name = "";
448 /* Initialise stat info for passing to tap */
450 if (pi_current == MAX_MGCP_MESSAGES_IN_PACKET)
452 /* Overwrite info in first struct if run out of space... */
455 mi = &pi_arr[pi_current];
458 mi->mgcp_type = MGCP_OTHERS;
461 mi->req_time.secs = 0;
462 mi->req_time.nsecs = 0;
463 mi->is_duplicate = FALSE;
464 mi->request_available = FALSE;
466 mi->endpointId = NULL;
467 mi->observedEvents = NULL;
469 mi->signalReq = NULL;
470 mi->hasDigitMap = FALSE;
472 /* Initialize variables */
474 tvb_sectionbegin = tvb_sectionend;
476 tvb_len = tvb_length(tvb);
477 tvb_current_len = tvb_len;
480 * Check to see whether we're really dealing with MGCP by looking
481 * for a valid MGCP verb or response code. This isn't infallible,
482 * but its cheap and its better than nothing.
484 if (is_mgcp_verb(tvb,0,tvb_len,&verb_name) || is_mgcp_rspcode(tvb,0,tvb_len))
486 /* dissect first line */
487 tvb_sectionbegin = 0;
488 tvb_current_len = tvb_len;
489 tvb_sectionend = tvb_sectionbegin;
490 sectionlen = tvb_find_line_end(tvb,0,-1,&tvb_sectionend,FALSE);
493 dissect_mgcp_firstline(tvb_new_subset(tvb, tvb_sectionbegin,
494 sectionlen,-1), pinfo,
497 tvb_sectionbegin = tvb_sectionend;
500 if (tvb_sectionbegin < tvb_len)
502 sectionlen = tvb_find_null_line(tvb, tvb_sectionbegin, -1,
506 dissect_mgcp_params(tvb_new_subset(tvb, tvb_sectionbegin, sectionlen, -1),
508 tvb_sectionbegin = tvb_sectionend;
512 /* Set the mgcp payload length correctly so we don't include any
514 sectionlen = tvb_sectionend;
515 proto_item_set_len(ti,sectionlen);
517 /* Display the raw text of the mgcp message if desired */
519 /* Do we want to display the raw text of our MGCP packet? */
520 if (global_mgcp_raw_text)
523 mgcp_raw_text_add(tvb, mgcp_tree);
526 /* Dissect sdp payload */
527 if (tvb_sectionend < tvb_len)
529 next_tvb = tvb_new_subset(tvb, tvb_sectionend, -1, -1);
530 call_dissector(sdp_handle, next_tvb, pinfo, tree);
537 * Add the raw text of the message to the dissect tree if appropriate
538 * preferences are specified.
540 static void mgcp_raw_text_add(tvbuff_t *tvb, proto_tree *tree)
542 gint tvb_linebegin,tvb_lineend,tvb_len,linelen;
545 tvb_len = tvb_length(tvb);
549 tvb_find_line_end(tvb,tvb_linebegin,-1,&tvb_lineend,FALSE);
550 linelen = tvb_lineend - tvb_linebegin;
551 proto_tree_add_text(tree, tvb, tvb_linebegin, linelen, "%s",
552 tvb_format_text(tvb, tvb_linebegin, linelen));
553 tvb_linebegin = tvb_lineend;
554 } while (tvb_lineend < tvb_len);
557 /* Discard and init any state we've saved */
558 static void mgcp_init_protocol(void)
560 if (mgcp_calls != NULL)
562 g_hash_table_destroy(mgcp_calls);
565 if (mgcp_call_info_key_chunk != NULL)
567 g_mem_chunk_destroy(mgcp_call_info_key_chunk);
568 mgcp_call_info_key_chunk = NULL;
570 if (mgcp_call_info_value_chunk != NULL)
572 g_mem_chunk_destroy(mgcp_call_info_value_chunk);
573 mgcp_call_info_value_chunk = NULL;
576 mgcp_calls = g_hash_table_new(mgcp_call_hash, mgcp_call_equal);
577 mgcp_call_info_key_chunk = g_mem_chunk_new("call_info_key_chunk",
578 sizeof(mgcp_call_info_key),
579 200 * sizeof(mgcp_call_info_key),
581 mgcp_call_info_value_chunk = g_mem_chunk_new("call_info_value_chunk",
583 200 * sizeof(mgcp_call_t),
587 /* Register all the bits needed with the filtering engine */
588 void proto_register_mgcp(void)
590 static hf_register_info hf[] =
593 { "Request", "mgcp.req", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
594 "True if MGCP request", HFILL }},
596 { "Response", "mgcp.rsp", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
597 "TRUE if MGCP response", HFILL }},
598 { &hf_mgcp_req_frame,
599 { "Request Frame", "mgcp.reqframe", FT_FRAMENUM, BASE_NONE, NULL, 0,
600 "Request Frame", HFILL }},
601 { &hf_mgcp_rsp_frame,
602 { "Response Frame", "mgcp.rspframe", FT_FRAMENUM, BASE_NONE, NULL, 0,
603 "Response Frame", HFILL }},
605 { "Time from request", "mgcp.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0,
606 "Timedelta between Request and Response", HFILL }},
608 { "Verb", "mgcp.req.verb", FT_STRING, BASE_DEC, NULL, 0x0,
609 "Name of the verb", HFILL }},
610 { &hf_mgcp_req_endpoint,
611 { "Endpoint", "mgcp.req.endpoint", FT_STRING, BASE_DEC, NULL, 0x0,
612 "Endpoint referenced by the message", HFILL }},
614 { "Transaction ID", "mgcp.transid", FT_STRING, BASE_DEC, NULL, 0x0,
615 "Transaction ID of this message", HFILL }},
617 { "Version", "mgcp.version", FT_STRING, BASE_DEC, NULL, 0x0,
618 "MGCP Version", HFILL }},
619 { &hf_mgcp_rsp_rspcode,
620 { "Response Code", "mgcp.rsp.rspcode", FT_UINT32, BASE_DEC, VALS(mgcp_return_code_vals), 0x0,
621 "Response Code", HFILL }},
622 { &hf_mgcp_rsp_rspstring,
623 { "Response String", "mgcp.rsp.rspstring", FT_STRING, BASE_DEC, NULL, 0x0,
624 "Response String", HFILL }},
626 { "Parameters", "mgcp.params", FT_NONE, 0, NULL, 0x0,
627 "MGCP parameters", HFILL }},
628 { &hf_mgcp_param_rspack,
629 { "ResponseAck (K)", "mgcp.param.rspack", FT_STRING, BASE_DEC, NULL, 0x0,
630 "Response Ack", HFILL }},
631 { &hf_mgcp_param_bearerinfo,
632 { "BearerInformation (B)", "mgcp.param.bearerinfo", FT_STRING, BASE_DEC, NULL, 0x0,
633 "Bearer Information", HFILL }},
634 { &hf_mgcp_param_callid,
635 { "CallId (C)", "mgcp.param.callid", FT_STRING, BASE_DEC, NULL, 0x0,
637 { &hf_mgcp_param_connectionid,
638 {"ConnectionIdentifier (I)", "mgcp.param.connectionid", FT_STRING, BASE_DEC, NULL, 0x0,
639 "Connection Identifier", HFILL }},
640 { &hf_mgcp_param_secondconnectionid,
641 { "SecondConnectionID (I2)", "mgcp.param.secondconnectionid", FT_STRING, BASE_DEC, NULL, 0x0,
642 "Second Connection Identifier", HFILL }},
643 { &hf_mgcp_param_notifiedentity,
644 { "NotifiedEntity (N)", "mgcp.param.notifiedentity", FT_STRING, BASE_DEC, NULL, 0x0,
645 "Notified Entity", HFILL }},
646 { &hf_mgcp_param_requestid,
647 { "RequestIdentifier (X)", "mgcp.param.requestid", FT_STRING, BASE_DEC, NULL, 0x0,
648 "Request Identifier", HFILL }},
649 { &hf_mgcp_param_localconnoptions,
650 { "LocalConnectionOptions (L)", "mgcp.param.localconnectionoptions", FT_STRING, BASE_DEC, NULL, 0x0,
651 "Local Connection Options", HFILL }},
652 { &hf_mgcp_param_localconnoptions_p,
653 { "Packetization period (p)", "mgcp.param.localconnectionoptions.p", FT_UINT32, BASE_DEC, NULL, 0x0,
654 "Packetization period", HFILL }},
655 { &hf_mgcp_param_localconnoptions_a,
656 { "Codecs (a)", "mgcp.param.localconnectionoptions.a", FT_STRING, BASE_DEC, NULL, 0x0,
658 { &hf_mgcp_param_localconnoptions_s,
659 { "Silence Suppression (s)", "mgcp.param.localconnectionoptions.s", FT_STRING, BASE_DEC, NULL, 0x0,
660 "Silence Suppression", HFILL }},
661 { &hf_mgcp_param_localconnoptions_e,
662 { "Echo Cancellation (e)", "mgcp.param.localconnectionoptions.e", FT_STRING, BASE_DEC, NULL, 0x0,
663 "Echo Cancellation", HFILL }},
664 { &hf_mgcp_param_localconnoptions_scrtp,
665 { "RTP ciphersuite (sc-rtp)", "mgcp.param.localconnectionoptions.scrtp", FT_STRING, BASE_DEC, NULL, 0x0,
666 "RTP ciphersuite", HFILL }},
667 { &hf_mgcp_param_localconnoptions_scrtcp,
668 { "RTCP ciphersuite (sc-rtcp)", "mgcp.param.localconnectionoptions.scrtcp", FT_STRING, BASE_DEC, NULL, 0x0,
669 "RTCP ciphersuite", HFILL }},
670 { &hf_mgcp_param_localconnoptions_b,
671 { "Bandwidth (b)", "mgcp.param.localconnectionoptions.b", FT_STRING, BASE_DEC, NULL, 0x0,
672 "Bandwidth", HFILL }},
673 { &hf_mgcp_param_localconnoptions_esccd,
674 { "Content Destination (es-ccd)", "mgcp.param.localconnectionoptions.esccd", FT_STRING, BASE_DEC, NULL, 0x0,
675 "Content Destination", HFILL }},
676 { &hf_mgcp_param_localconnoptions_escci,
677 { "Content Identifier (es-cci)", "mgcp.param.localconnectionoptions.escci", FT_STRING, BASE_DEC, NULL, 0x0,
678 "Content Identifier", HFILL }},
679 { &hf_mgcp_param_localconnoptions_dqgi,
680 { "D-QoS GateID (dq-gi)", "mgcp.param.localconnectionoptions.dqgi", FT_STRING, BASE_DEC, NULL, 0x0,
681 "D-QoS GateID", HFILL }},
682 { &hf_mgcp_param_localconnoptions_dqrd,
683 { "D-QoS Reserve Destination (dq-rd)", "mgcp.param.localconnectionoptions.dqrd", FT_STRING, BASE_DEC, NULL, 0x0,
684 "D-QoS Reserve Destination", HFILL }},
685 { &hf_mgcp_param_localconnoptions_dqri,
686 { "D-QoS Resource ID (dq-ri)", "mgcp.param.localconnectionoptions.dqri", FT_STRING, BASE_DEC, NULL, 0x0,
687 "D-QoS Resource ID", HFILL }},
688 { &hf_mgcp_param_localconnoptions_dqrr,
689 { "D-QoS Resource Reservation (dq-rr)", "mgcp.param.localconnectionoptions.dqrr", FT_STRING, BASE_DEC, NULL, 0x0,
690 "D-QoS Resource Reservation", HFILL }},
691 { &hf_mgcp_param_localconnoptions_k,
692 { "Encryption Key (k)", "mgcp.param.localconnectionoptions.k", FT_STRING, BASE_DEC, NULL, 0x0,
693 "Encryption Key", HFILL }},
694 { &hf_mgcp_param_localconnoptions_gc,
695 { "Gain Control (gc)", "mgcp.param.localconnectionoptions.gc", FT_UINT32, BASE_DEC, NULL, 0x0,
696 "Gain Control", HFILL }},
697 { &hf_mgcp_param_localconnoptions_fmtp,
698 { "Media Format (fmtp)", "mgcp.param.localconnectionoptions.fmtp", FT_STRING, BASE_DEC, NULL, 0x0,
699 "Media Format", HFILL }},
700 { &hf_mgcp_param_localconnoptions_nt,
701 { "Network Type (nt)", "mgcp.param.localconnectionoptions.nt", FT_STRING, BASE_DEC, NULL, 0x0,
702 "Network Type", HFILL }},
703 { &hf_mgcp_param_localconnoptions_ofmtp,
704 { "Optional Media Format (o-fmtp)", "mgcp.param.localconnectionoptions.ofmtp", FT_STRING, BASE_DEC, NULL, 0x0,
705 "Optional Media Format", HFILL }},
706 { &hf_mgcp_param_localconnoptions_r,
707 { "Resource Reservation (r)", "mgcp.param.localconnectionoptions.r", FT_STRING, BASE_DEC, NULL, 0x0,
708 "Resource Reservation", HFILL }},
709 { &hf_mgcp_param_localconnoptions_t,
710 { "Type of Service (r)", "mgcp.param.localconnectionoptions.t", FT_STRING, BASE_DEC, NULL, 0x0,
711 "Type of Service", HFILL }},
712 { &hf_mgcp_param_localconnoptions_rcnf,
713 { "Reservation Confirmation (r-cnf)", "mgcp.param.localconnectionoptions.rcnf", FT_STRING, BASE_DEC, NULL, 0x0,
714 "Reservation Confirmation", HFILL }},
715 { &hf_mgcp_param_localconnoptions_rdir,
716 { "Reservation Direction (r-dir)", "mgcp.param.localconnectionoptions.rdir", FT_STRING, BASE_DEC, NULL, 0x0,
717 "Reservation Direction", HFILL }},
718 { &hf_mgcp_param_localconnoptions_rsh,
719 { "Resource Sharing (r-sh)", "mgcp.param.localconnectionoptions.rsh", FT_STRING, BASE_DEC, NULL, 0x0,
720 "Resource Sharing", HFILL }},
721 { &hf_mgcp_param_connectionmode,
722 { "ConnectionMode (M)", "mgcp.param.connectionmode", FT_STRING, BASE_DEC, NULL, 0x0,
723 "Connection Mode", HFILL }},
724 { &hf_mgcp_param_reqevents,
725 { "RequestedEvents (R)", "mgcp.param.reqevents", FT_STRING, BASE_DEC, NULL, 0x0,
726 "Requested Events", HFILL }},
727 { &hf_mgcp_param_signalreq,
728 { "SignalRequests (S)", "mgcp.param.signalreq", FT_STRING, BASE_DEC, NULL, 0x0,
729 "Signal Request", HFILL }},
730 { &hf_mgcp_param_restartmethod,
731 { "RestartMethod (RM)", "mgcp.param.restartmethod", FT_STRING, BASE_DEC, NULL, 0x0,
732 "Restart Method", HFILL }},
733 { &hf_mgcp_param_restartdelay,
734 { "RestartDelay (RD)", "mgcp.param.restartdelay", FT_STRING, BASE_DEC, NULL, 0x0,
735 "Restart Delay", HFILL }},
736 { &hf_mgcp_param_digitmap,
737 { "DigitMap (D)", "mgcp.param.digitmap", FT_STRING, BASE_DEC, NULL, 0x0,
738 "Digit Map", HFILL }},
739 { &hf_mgcp_param_observedevent,
740 { "ObservedEvents (O)", "mgcp.param.observedevents", FT_STRING, BASE_DEC, NULL, 0x0,
741 "Observed Events", HFILL }},
742 { &hf_mgcp_param_connectionparam,
743 { "ConnectionParameters (P)", "mgcp.param.connectionparam", FT_STRING, BASE_DEC, NULL, 0x0,
744 "Connection Parameters", HFILL }},
745 { &hf_mgcp_param_connectionparam_ps,
746 { "Packets sent (PS)", "mgcp.param.connectionparam.ps", FT_UINT32, BASE_DEC, NULL, 0x0,
747 "Packets sent (P:PS)", HFILL }},
748 { &hf_mgcp_param_connectionparam_os,
749 { "Octets sent (OS)", "mgcp.param.connectionparam.os", FT_UINT32, BASE_DEC, NULL, 0x0,
750 "Octets sent (P:OS)", HFILL }},
751 { &hf_mgcp_param_connectionparam_pr,
752 { "Packets received (PR)", "mgcp.param.connectionparam.pr", FT_UINT32, BASE_DEC, NULL, 0x0,
753 "Packets received (P:PR)", HFILL }},
754 { &hf_mgcp_param_connectionparam_or,
755 { "Octets received (OR)", "mgcp.param.connectionparam.or", FT_UINT32, BASE_DEC, NULL, 0x0,
756 "Octets received (P:OR)", HFILL }},
757 { &hf_mgcp_param_connectionparam_pl,
758 { "Packets lost (PL)", "mgcp.param.connectionparam.pl", FT_UINT32, BASE_DEC, NULL, 0x0,
759 "Packets lost (P:PL)", HFILL }},
760 { &hf_mgcp_param_connectionparam_ji,
761 { "Jitter (JI)", "mgcp.param.connectionparam.ji", FT_UINT32, BASE_DEC, NULL, 0x0,
762 "Average inter-packet arrival jitter in milliseconds (P:JI)", HFILL }},
763 { &hf_mgcp_param_connectionparam_la,
764 { "Latency (LA)", "mgcp.param.connectionparam.la", FT_UINT32, BASE_DEC, NULL, 0x0,
765 "Average latency in milliseconds (P:LA)", HFILL }},
766 { &hf_mgcp_param_connectionparam_pcrps,
767 { "Remote Packets sent (PC/RPS)", "mgcp.param.connectionparam.pcrps", FT_UINT32, BASE_DEC, NULL, 0x0,
768 "Remote Packets sent (P:PC/RPS)", HFILL }},
769 { &hf_mgcp_param_connectionparam_pcros,
770 { "Remote Octets sent (PC/ROS)", "mgcp.param.connectionparam.pcros", FT_UINT32, BASE_DEC, NULL, 0x0,
771 "Remote Octets sent (P:PC/ROS)", HFILL }},
772 { &hf_mgcp_param_connectionparam_pcrpl,
773 { "Remote Packets lost (PC/RPL)", "mgcp.param.connectionparam.pcrpl", FT_UINT32, BASE_DEC, NULL, 0x0,
774 "Remote Packets lost (P:PC/RPL)", HFILL }},
775 { &hf_mgcp_param_connectionparam_pcrji,
776 { "Remote Jitter (PC/RJI)", "mgcp.param.connectionparam.pcrji", FT_UINT32, BASE_DEC, NULL, 0x0,
777 "Remote Jitter (P:PC/RJI)", HFILL }},
778 { &hf_mgcp_param_connectionparam_x,
779 { "Vendor Extension", "mgcp.param.connectionparam.x", FT_STRING, BASE_DEC, NULL, 0x0,
780 "Vendor Extension (P:X-*)", HFILL }},
781 { &hf_mgcp_param_reasoncode,
782 { "ReasonCode (E)", "mgcp.param.reasoncode", FT_STRING, BASE_DEC, NULL, 0x0,
783 "Reason Code", HFILL }},
784 { &hf_mgcp_param_eventstates,
785 { "EventStates (ES)", "mgcp.param.eventstates", FT_STRING, BASE_DEC, NULL, 0x0,
786 "Event States", HFILL }},
787 { &hf_mgcp_param_specificendpoint,
788 { "SpecificEndpointID (Z)", "mgcp.param.specificendpointid", FT_STRING, BASE_DEC, NULL, 0x0,
789 "Specific Endpoint ID", HFILL }},
790 { &hf_mgcp_param_secondendpointid,
791 { "SecondEndpointID (Z2)", "mgcp.param.secondendpointid", FT_STRING, BASE_DEC, NULL, 0x0,
792 "Second Endpoing ID", HFILL }},
793 { &hf_mgcp_param_reqinfo,
794 { "RequestedInfo (F)", "mgcp.param.reqinfo", FT_STRING, BASE_DEC, NULL, 0x0,
795 "Requested Info", HFILL }},
796 { &hf_mgcp_param_quarantinehandling,
797 { "QuarantineHandling (Q)", "mgcp.param.quarantinehandling", FT_STRING, BASE_DEC, NULL, 0x0,
798 "Quarantine Handling", HFILL }},
799 { &hf_mgcp_param_detectedevents,
800 { "DetectedEvents (T)", "mgcp.param.detectedevents", FT_STRING, BASE_DEC, NULL, 0x0,
801 "Detected Events", HFILL }},
802 { &hf_mgcp_param_capabilities,
803 { "Capabilities (A)", "mgcp.param.capabilities", FT_STRING, BASE_DEC, NULL, 0x0,
804 "Capabilities", HFILL }},
805 { &hf_mgcp_param_maxmgcpdatagram,
806 {"MaxMGCPDatagram (MD)", "mgcp.param.maxmgcpdatagram", FT_STRING, BASE_DEC, NULL, 0x0,
807 "Maximum MGCP Datagram size", HFILL }},
808 { &hf_mgcp_param_packagelist,
809 {"PackageList (PL)", "mgcp.param.packagelist", FT_STRING, BASE_DEC, NULL, 0x0,
810 "Package List", HFILL }},
811 { &hf_mgcp_param_extension,
812 { "Extension Parameter (non-critical)", "mgcp.param.extension", FT_STRING, BASE_DEC, NULL, 0x0,
813 "Extension Parameter", HFILL }},
814 { &hf_mgcp_param_extension_critical,
815 { "Extension Parameter (critical)", "mgcp.param.extensioncritical", FT_STRING, BASE_DEC, NULL, 0x0,
816 "Critical Extension Parameter", HFILL }},
817 { &hf_mgcp_param_invalid,
818 { "Invalid Parameter", "mgcp.param.invalid", FT_STRING, BASE_DEC, NULL, 0x0,
819 "Invalid Parameter", HFILL }},
820 { &hf_mgcp_messagecount,
821 { "MGCP Message Count", "mgcp.messagecount", FT_UINT32, BASE_DEC, NULL, 0x0,
822 "Number of MGCP message in a packet", HFILL }},
824 { "Duplicate Message", "mgcp.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
825 "Duplicate Message", HFILL }},
827 { "Duplicate Request", "mgcp.req.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
828 "Duplicate Request", HFILL }},
830 { "Duplicate Response", "mgcp.rsp.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
831 "Duplicate Response", HFILL }},
838 &ett_mgcp_param_connectionparam,
839 &ett_mgcp_param_localconnectionoptions
842 module_t *mgcp_module;
844 /* Register protocol */
845 proto_mgcp = proto_register_protocol("Media Gateway Control Protocol", "MGCP", "mgcp");
846 proto_register_field_array(proto_mgcp, hf, array_length(hf));
847 proto_register_subtree_array(ett, array_length(ett));
848 register_init_routine(&mgcp_init_protocol);
850 /* Register our configuration options */
851 mgcp_module = prefs_register_protocol(proto_mgcp, proto_reg_handoff_mgcp);
853 prefs_register_uint_preference(mgcp_module, "tcp.gateway_port",
854 "MGCP Gateway TCP Port",
855 "Set the UDP port for gateway messages "
856 "(if other than the default of 2427)",
857 10, &global_mgcp_gateway_tcp_port);
859 prefs_register_uint_preference(mgcp_module, "udp.gateway_port",
860 "MGCP Gateway UDP Port",
861 "Set the TCP port for gateway messages "
862 "(if other than the default of 2427)",
863 10, &global_mgcp_gateway_udp_port);
865 prefs_register_uint_preference(mgcp_module, "tcp.callagent_port",
866 "MGCP Callagent TCP Port",
867 "Set the TCP port for callagent messages "
868 "(if other than the default of 2727)",
869 10, &global_mgcp_callagent_tcp_port);
871 prefs_register_uint_preference(mgcp_module, "udp.callagent_port",
872 "MGCP Callagent UDP Port",
873 "Set the UDP port for callagent messages "
874 "(if other than the default of 2727)",
875 10, &global_mgcp_callagent_udp_port);
878 prefs_register_bool_preference(mgcp_module, "display_raw_text",
879 "Display raw text for MGCP message",
880 "Specifies that the raw text of the "
881 "MGCP message should be displayed "
882 "instead of (or in addition to) the "
884 &global_mgcp_raw_text);
886 prefs_register_obsolete_preference(mgcp_module, "display_dissect_tree");
888 prefs_register_bool_preference(mgcp_module, "display_mgcp_message_count",
889 "Display the number of MGCP messages",
890 "Display the number of MGCP messages "
891 "found in a packet in the protocol column.",
892 &global_mgcp_message_count);
894 mgcp_tap = register_tap("mgcp");
897 /* The registration hand-off routine */
898 void proto_reg_handoff_mgcp(void)
900 static int mgcp_prefs_initialized = FALSE;
901 static dissector_handle_t mgcp_handle;
903 /* Get a handle for the SDP dissector. */
904 sdp_handle = find_dissector("sdp");
906 if (!mgcp_prefs_initialized)
908 mgcp_handle = create_dissector_handle(dissect_mgcp, proto_mgcp);
909 mgcp_prefs_initialized = TRUE;
913 dissector_delete("tcp.port", gateway_tcp_port, mgcp_handle);
914 dissector_delete("udp.port", gateway_udp_port, mgcp_handle);
915 dissector_delete("tcp.port", callagent_tcp_port, mgcp_handle);
916 dissector_delete("udp.port", callagent_udp_port, mgcp_handle);
919 /* Set our port number for future use */
920 gateway_tcp_port = global_mgcp_gateway_tcp_port;
921 gateway_udp_port = global_mgcp_gateway_udp_port;
923 callagent_tcp_port = global_mgcp_callagent_tcp_port;
924 callagent_udp_port = global_mgcp_callagent_udp_port;
926 dissector_add("tcp.port", global_mgcp_gateway_tcp_port, mgcp_handle);
927 dissector_add("udp.port", global_mgcp_gateway_udp_port, mgcp_handle);
928 dissector_add("tcp.port", global_mgcp_callagent_tcp_port, mgcp_handle);
929 dissector_add("udp.port", global_mgcp_callagent_udp_port, mgcp_handle);
933 * is_mgcp_verb - A function for determining whether there is a
934 * MGCP verb at offset in tvb
937 * tvb - The tvbuff in which we are looking for an MGCP verb
938 * offset - The offset in tvb at which we are looking for a MGCP verb
939 * maxlength - The maximum distance from offset we may look for the
940 * characters that make up a MGCP verb.
941 * verb_name - The name for the verb code found (output)
943 * Return: TRUE if there is an MGCP verb at offset in tvb, otherwise FALSE
945 static gboolean is_mgcp_verb(tvbuff_t *tvb, gint offset, gint maxlength, const gchar **verb_name)
947 int returnvalue = FALSE;
950 /* Read the string into 'word' and see if it looks like the start of a verb */
951 if ((maxlength >= 4) && tvb_get_nstringz0(tvb, offset, sizeof(word), word))
953 if (((strncasecmp(word, "EPCF", 4) == 0) && (*verb_name = "EndpointConfiguration|")) ||
954 ((strncasecmp(word, "CRCX", 4) == 0) && (*verb_name = "CreateConnection")) ||
955 ((strncasecmp(word, "MDCX", 4) == 0) && (*verb_name = "ModifyConnection")) ||
956 ((strncasecmp(word, "DLCX", 4) == 0) && (*verb_name = "DeleteConnection")) ||
957 ((strncasecmp(word, "RQNT", 4) == 0) && (*verb_name = "NotificationRequest")) ||
958 ((strncasecmp(word, "NTFY", 4) == 0) && (*verb_name = "Notify")) ||
959 ((strncasecmp(word, "AUEP", 4) == 0) && (*verb_name = "AuditEndpoint")) ||
960 ((strncasecmp(word, "AUCX", 4) == 0) && (*verb_name = "AuditConnection")) ||
961 ((strncasecmp(word, "RSIP", 4) == 0) && (*verb_name = "RestartInProgress")) ||
962 ((strncasecmp(word, "MESG", 4) == 0) && (*verb_name = "Message")) ||
963 (word[0] == 'X' && is_rfc2234_alpha(word[1]) && is_rfc2234_alpha(word[2]) &&
964 is_rfc2234_alpha(word[3]) && (*verb_name = "*Experimental*")))
970 /* May be whitespace after verb code - anything else is an error.. */
971 if (returnvalue && maxlength >= 5)
973 char next = tvb_get_guint8(tvb,4);
974 if ((next != ' ') && (next != '\t'))
984 * is_mgcp_rspcode - A function for determining whether something which
985 * looks roughly like a MGCP response code (3-digit number)
986 * is at 'offset' in tvb
989 * tvb - The tvbuff in which we are looking for an MGCP response code
990 * offset - The offset in tvb at which we are looking for a MGCP response code
991 * maxlength - The maximum distance from offset we may look for the
992 * characters that make up a MGCP response code.
994 * Return: TRUE if there is an MGCP response code at offset in tvb,
997 static gboolean is_mgcp_rspcode(tvbuff_t *tvb, gint offset, gint maxlength)
999 int returnvalue = FALSE;
1002 /* Do 1st 3 characters look like digits? */
1005 tvb_get_nstringz0(tvb, offset, sizeof(word), word);
1006 if (isdigit(word[0]) && isdigit(word[1]) && isdigit(word[2]))
1012 /* Maybe some white space after the 3rd digit - anything else is an error */
1013 if (returnvalue && maxlength >= 4)
1015 char next = tvb_get_guint8(tvb, 3);
1016 if ((next != ' ') && (next != '\t'))
1018 returnvalue = FALSE;
1026 * is_rfc2234_alpha - Indicates whether the character c is an alphabetical
1027 * character. This function is used instead of
1028 * isalpha because isalpha may deviate from the rfc2234
1029 * definition of ALPHA in some locales.
1032 * c - The character being checked for being an alphabetical character.
1034 * Return: TRUE if c is an upper or lower case alphabetical character,
1037 static gboolean is_rfc2234_alpha(guint8 c)
1039 return ((c <= 'Z' && c >= 'A' ) || (c <= 'z' && c >= 'a'));
1044 * tvb_parse_param - Parse the MGCP param into a type and a value.
1047 * tvb - The tvbuff containing the MGCP param we are to parse.
1048 * offset - The offset in tvb at which we will begin looking for a
1049 * MGCP parameter to parse.
1050 * len - The maximum distance from offset in tvb that we can look for
1051 * an MGCP parameter to parse.
1052 * hf - The place to write a pointer to the integer representing the
1053 * header field associated with the MGCP parameter parsed.
1055 * Returns: The offset in tvb where the value of the MGCP parameter
1058 static gint tvb_parse_param(tvbuff_t* tvb, gint offset, gint len, int** hf)
1060 gint returnvalue = -1, tvb_current_offset,counter;
1061 guint8 tempchar, plus_minus;
1064 tvb_current_offset = offset;
1070 tempchar = tvb_get_guint8(tvb,tvb_current_offset);
1075 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1077 *hf = &hf_mgcp_param_invalid;
1080 *hf = &hf_mgcp_param_rspack;
1083 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1085 *hf = &hf_mgcp_param_invalid;
1088 *hf = &hf_mgcp_param_bearerinfo;
1091 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1093 *hf = &hf_mgcp_param_invalid;
1096 *hf = &hf_mgcp_param_callid;
1099 tvb_current_offset++;
1100 if (len > (tvb_current_offset - offset) &&
1101 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1103 *hf = &hf_mgcp_param_connectionid;
1104 tvb_current_offset--;
1107 if (tempchar == '2')
1109 *hf = &hf_mgcp_param_secondconnectionid;
1113 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1115 *hf = &hf_mgcp_param_invalid;
1118 *hf = &hf_mgcp_param_notifiedentity;
1122 tvb_current_offset++;
1124 /* X: is RequestIdentifier */
1125 if (len > (tvb_current_offset - offset) &&
1126 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1128 *hf = &hf_mgcp_param_requestid;
1129 tvb_current_offset--;
1132 /* X+...: or X-....: are vendor extension parameters */
1134 if (len > (tvb_current_offset - offset) &&
1135 ((plus_minus = tvb_get_guint8(tvb,tvb_current_offset)) == '-' ||
1136 (plus_minus == '+')))
1138 /* Move past + or - */
1139 tvb_current_offset++;
1141 /* Keep going, through possible vendor param name */
1143 ((len > (counter + tvb_current_offset-offset)) &&
1144 (is_rfc2234_alpha(tempchar = tvb_get_guint8(tvb, tvb_current_offset+counter)) ||
1145 isdigit(tempchar))) ;
1148 if (tempchar == ':')
1150 /* Looks like a valid vendor param name */
1151 tvb_current_offset += counter;
1155 *hf = &hf_mgcp_param_extension_critical;
1158 *hf = &hf_mgcp_param_extension;
1165 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1167 *hf = &hf_mgcp_param_invalid;
1170 *hf = &hf_mgcp_param_localconnoptions;
1173 tvb_current_offset++;
1174 if (len > (tvb_current_offset - offset) &&
1175 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1177 *hf = &hf_mgcp_param_connectionmode;
1178 tvb_current_offset--;
1181 if (tempchar == 'D')
1183 *hf = &hf_mgcp_param_maxmgcpdatagram;
1187 tvb_current_offset++;
1188 if (len > (tvb_current_offset - offset) &&
1189 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1191 *hf = &hf_mgcp_param_reqevents;
1192 tvb_current_offset--;
1195 if ( tempchar == 'M')
1197 *hf = &hf_mgcp_param_restartmethod;
1200 if (tempchar == 'D')
1202 *hf = &hf_mgcp_param_restartdelay;
1206 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1208 *hf = &hf_mgcp_param_invalid;
1211 *hf = &hf_mgcp_param_signalreq;
1212 buf = &(mi->signalReq);
1215 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1217 *hf = &hf_mgcp_param_invalid;
1220 *hf = &hf_mgcp_param_digitmap;
1221 mi->hasDigitMap = TRUE;
1224 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1226 *hf = &hf_mgcp_param_invalid;
1229 *hf = &hf_mgcp_param_observedevent;
1230 buf = &(mi->observedEvents);
1233 tvb_current_offset++;
1234 if (len > (tvb_current_offset - offset) &&
1235 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1237 *hf = &hf_mgcp_param_connectionparam;
1238 tvb_current_offset--;
1241 if ( tempchar == 'L')
1243 *hf = &hf_mgcp_param_packagelist;
1247 tvb_current_offset++;
1248 if (len > (tvb_current_offset - offset) &&
1249 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1251 *hf = &hf_mgcp_param_reasoncode;
1252 tvb_current_offset--;
1255 if ( tempchar == 'S')
1257 *hf = &hf_mgcp_param_eventstates;
1261 tvb_current_offset++;
1262 if (len > (tvb_current_offset - offset) &&
1263 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1265 *hf = &hf_mgcp_param_specificendpoint;
1266 tvb_current_offset--;
1269 if (tempchar == '2')
1271 *hf = &hf_mgcp_param_secondendpointid;
1275 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1277 *hf = &hf_mgcp_param_invalid;
1280 *hf = &hf_mgcp_param_reqinfo;
1283 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1285 *hf = &hf_mgcp_param_invalid;
1288 *hf = &hf_mgcp_param_quarantinehandling;
1291 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1293 *hf = &hf_mgcp_param_invalid;
1296 *hf = &hf_mgcp_param_detectedevents;
1299 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1301 *hf = &hf_mgcp_param_invalid;
1304 *hf = &hf_mgcp_param_capabilities;
1308 *hf = &hf_mgcp_param_invalid;
1312 /* Move to (hopefully) the colon */
1313 tvb_current_offset++;
1315 /* Add a recognised parameter type if we have one */
1316 if (*hf != NULL && len > (tvb_current_offset - offset) &&
1317 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1319 tvb_current_offset++;
1320 tvb_current_offset = tvb_skip_wsp(tvb,tvb_current_offset, (len - tvb_current_offset + offset));
1321 returnvalue = tvb_current_offset;
1323 /* set the observedEvents or signalReq used in Voip Calls analysis */
1325 *buf = tvb_get_ephemeral_string(tvb, tvb_current_offset, (len - tvb_current_offset + offset));
1331 /* Was an empty line */
1332 *hf = &hf_mgcp_param_invalid;
1335 /* For these types, show the whole line */
1336 if ((*hf == &hf_mgcp_param_invalid) ||
1337 (*hf == &hf_mgcp_param_extension) || (*hf == &hf_mgcp_param_extension_critical))
1339 returnvalue = offset;
1347 * dissect_mgcp_firstline - Dissects the firstline of an MGCP message.
1348 * Adds the appropriate headers fields to
1349 * tree for the dissection of the first line
1350 * of an MGCP message.
1353 * tvb - The tvb containing the first line of an MGCP message. This
1354 * tvb is presumed to ONLY contain the first line of the MGCP
1356 * pinfo - The packet info for the packet. This is not really used
1357 * by this function but is passed through so as to retain the
1358 * style of a dissector.
1359 * tree - The tree from which to hang the structured information parsed
1360 * from the first line of the MGCP message.
1362 static void dissect_mgcp_firstline(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1364 gint tvb_current_offset,tvb_previous_offset,tvb_len,tvb_current_len;
1365 gint tokennum, tokenlen;
1366 char *transid = NULL;
1368 char *endpointId = NULL;
1369 mgcp_type_t mgcp_type = MGCP_OTHERS;
1370 conversation_t* conversation;
1371 mgcp_call_info_key mgcp_call_key;
1372 mgcp_call_info_key *new_mgcp_call_key = NULL;
1373 mgcp_call_t *mgcp_call = NULL;
1376 const gchar *verb_description = "";
1377 char code_with_verb[64] = ""; /* To fit "<4-letter-code> (<longest-verb>)" */
1379 static address null_address = { AT_NONE, 0, NULL };
1380 tvb_previous_offset = 0;
1381 tvb_len = tvb_length(tvb);
1382 tvb_current_len = tvb_len;
1383 tvb_current_offset = tvb_previous_offset;
1384 mi->is_duplicate = FALSE;
1385 mi->request_available = FALSE;
1393 tvb_current_len = tvb_length_remaining(tvb,tvb_previous_offset);
1394 tvb_current_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_current_len, ' ');
1395 if (tvb_current_offset == -1)
1397 tvb_current_offset = tvb_len;
1398 tokenlen = tvb_current_len;
1402 tokenlen = tvb_current_offset - tvb_previous_offset;
1407 THROW(ReportedBoundsError);
1408 code = tvb_format_text(tvb,tvb_previous_offset,tokenlen);
1409 strncpy(mi->code,code,4);
1411 if (is_mgcp_verb(tvb,tvb_previous_offset,tvb_current_len,&verb_description))
1413 mgcp_type = MGCP_REQUEST;
1414 if (verb_description != NULL)
1416 /* Can show verb along with code if known */
1417 sprintf(code_with_verb, "%s (%s)", code, verb_description);
1420 proto_tree_add_string_format(tree, hf_mgcp_req_verb, tvb,
1421 tvb_previous_offset, tokenlen,
1423 strlen(code_with_verb) ? code_with_verb : code);
1426 if (is_mgcp_rspcode(tvb,tvb_previous_offset,tvb_current_len))
1428 mgcp_type = MGCP_RESPONSE;
1429 rspcode = atoi(code);
1430 mi->rspcode = rspcode;
1431 proto_tree_add_uint(tree,hf_mgcp_rsp_rspcode, tvb,
1432 tvb_previous_offset, tokenlen, rspcode);
1441 transid = tvb_format_text(tvb,tvb_previous_offset,tokenlen);
1442 /* XXX - what if this isn't a valid text string? */
1443 mi->transid = atol(transid);
1444 proto_tree_add_string(tree, hf_mgcp_transid, tvb,
1445 tvb_previous_offset, tokenlen, transid);
1449 if (mgcp_type == MGCP_REQUEST)
1451 endpointId = tvb_format_text(tvb, tvb_previous_offset,tokenlen);
1452 mi->endpointId = ep_strdup(endpointId);
1453 proto_tree_add_string(tree,hf_mgcp_req_endpoint, tvb,
1454 tvb_previous_offset, tokenlen, endpointId);
1457 if (mgcp_type == MGCP_RESPONSE)
1459 if (tvb_current_offset < tvb_len)
1461 tokenlen = tvb_find_line_end(tvb, tvb_previous_offset,
1462 -1, &tvb_current_offset, FALSE);
1466 tokenlen = tvb_current_len;
1468 proto_tree_add_string(tree, hf_mgcp_rsp_rspstring, tvb,
1469 tvb_previous_offset, tokenlen,
1470 tvb_format_text(tvb, tvb_previous_offset,
1476 if ((tokennum == 3 && mgcp_type == MGCP_REQUEST))
1478 if (tvb_current_offset < tvb_len )
1480 tokenlen = tvb_find_line_end(tvb, tvb_previous_offset,
1481 -1, &tvb_current_offset,FALSE);
1485 tokenlen = tvb_current_len;
1487 proto_tree_add_string(tree,hf_mgcp_version, tvb,
1488 tvb_previous_offset, tokenlen,
1489 tvb_format_text(tvb,tvb_previous_offset,
1493 if (tvb_current_offset < tvb_len)
1495 tvb_previous_offset = tvb_skip_wsp(tvb, tvb_current_offset,
1499 } while (tvb_current_offset < tvb_len && tvb_previous_offset < tvb_len && tokennum <= 3);
1504 proto_tree_add_boolean_hidden(tree, hf_mgcp_rsp, tvb, 0, 0, TRUE);
1505 /* Check for MGCP response. A response must match a call that
1506 we've seen, and the response must be sent to the same
1507 port and address that the call came from, and must
1508 come from the port to which the call was sent.
1510 If the transport is connection-oriented (we check, for
1511 now, only for "pinfo->ptype" of PT_TCP), we take
1512 into account the address from which the call was sent
1513 and the address to which the call was sent, because
1514 the addresses of the two endpoints should be the same
1515 for all calls and replies.
1517 If the transport is connectionless, we don't worry
1518 about the address to which the call was sent and from
1519 which the reply was sent, because there's no
1520 guarantee that the reply will come from the address
1521 to which the call was sent. */
1522 if (pinfo->ptype == PT_TCP)
1524 conversation = find_conversation(pinfo->fd->num, &pinfo->src,
1525 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1526 pinfo->destport, 0);
1530 /* XXX - can we just use NO_ADDR_B? Unfortunately,
1531 * you currently still have to pass a non-null
1532 * pointer for the second address argument even
1535 conversation = find_conversation(pinfo->fd->num, &null_address,
1536 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1537 pinfo->destport, 0);
1539 if (conversation != NULL)
1541 /* Look only for matching request, if
1542 matching conversation is available. */
1543 mgcp_call_key.transid = mi->transid;
1544 mgcp_call_key.conversation = conversation;
1545 mgcp_call = g_hash_table_lookup(mgcp_calls, &mgcp_call_key);
1548 /* Indicate the frame to which this is a reply. */
1549 if (mgcp_call->req_num)
1552 mi->request_available = TRUE;
1553 mgcp_call->responded = TRUE;
1554 mi->req_num = mgcp_call->req_num;
1555 strcpy(mi->code,mgcp_call->code);
1556 item = proto_tree_add_uint_format(tree, hf_mgcp_req_frame,
1557 tvb, 0, 0, mgcp_call->req_num,
1558 "This is a response to a request in frame %u",
1559 mgcp_call->req_num);
1560 PROTO_ITEM_SET_GENERATED(item);
1561 nstime_delta(&delta, &pinfo->fd->abs_ts, &mgcp_call->req_time);
1562 item = proto_tree_add_time(tree, hf_mgcp_time, tvb, 0, 0, &delta);
1563 PROTO_ITEM_SET_GENERATED(item);
1566 if (mgcp_call->rsp_num == 0)
1568 /* We have not yet seen a response to that call, so
1569 this must be the first response; remember its
1571 mgcp_call->rsp_num = pinfo->fd->num;
1575 /* We have seen a response to this call - but was it
1576 *this* response? (disregard provisional responses) */
1577 if ((mgcp_call->rsp_num != pinfo->fd->num) &&
1578 (mi->rspcode >= 200) &&
1579 (mi->rspcode == mgcp_call->rspcode))
1581 /* No, so it's a duplicate response. Mark it as such. */
1582 mi->is_duplicate = TRUE;
1583 if (check_col(pinfo->cinfo, COL_INFO))
1585 col_append_fstr(pinfo->cinfo, COL_INFO,
1586 ", Duplicate Response %u",
1592 proto_tree_add_uint_hidden(tree, hf_mgcp_dup, tvb, 0,0, mi->transid);
1593 item = proto_tree_add_uint(tree, hf_mgcp_rsp_dup,
1594 tvb, 0, 0, mi->transid);
1595 PROTO_ITEM_SET_GENERATED(item);
1599 /* Now store the response code (after comparison above) */
1600 mgcp_call->rspcode = mi->rspcode;
1605 proto_tree_add_boolean_hidden(tree, hf_mgcp_req, tvb, 0, 0, TRUE);
1606 /* Keep track of the address and port whence the call came,
1607 * and the port to which the call is being sent, so that
1608 * we can match up calls with replies.
1610 * If the transport is connection-oriented (we check, for
1611 * now, only for "pinfo->ptype" of PT_TCP), we take
1612 * into account the address from which the call was sent
1613 * and the address to which the call was sent, because
1614 * the addresses of the two endpoints should be the same
1615 * for all calls and replies.
1617 * If the transport is connectionless, we don't worry
1618 * about the address to which the call was sent and from
1619 * which the reply was sent, because there's no
1620 * guarantee that the reply will come from the address
1621 * to which the call was sent.
1623 if (pinfo->ptype == PT_TCP)
1625 conversation = find_conversation(pinfo->fd->num, &pinfo->src,
1626 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1627 pinfo->destport, 0);
1632 * XXX - can we just use NO_ADDR_B? Unfortunately,
1633 * you currently still have to pass a non-null
1634 * pointer for the second address argument even
1637 conversation = find_conversation(pinfo->fd->num, &pinfo->src,
1638 &null_address, pinfo->ptype, pinfo->srcport,
1639 pinfo->destport, 0);
1641 if (conversation == NULL)
1643 /* It's not part of any conversation - create a new one. */
1644 if (pinfo->ptype == PT_TCP)
1646 conversation = conversation_new(pinfo->fd->num, &pinfo->src,
1647 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1648 pinfo->destport, 0);
1652 conversation = conversation_new(pinfo->fd->num, &pinfo->src,
1653 &null_address, pinfo->ptype, pinfo->srcport,
1654 pinfo->destport, 0);
1658 /* Prepare the key data */
1659 mgcp_call_key.transid = mi->transid;
1660 mgcp_call_key.conversation = conversation;
1662 /* Look up the request */
1663 mgcp_call = g_hash_table_lookup(mgcp_calls, &mgcp_call_key);
1664 if (mgcp_call != NULL)
1666 /* We've seen a request with this TRANSID, with the same
1667 source and destination, before - but was it
1669 if (pinfo->fd->num != mgcp_call->req_num)
1671 /* No, so it's a duplicate request. Mark it as such. */
1672 mi->is_duplicate = TRUE;
1673 mi->req_num = mgcp_call->req_num;
1674 if (check_col(pinfo->cinfo, COL_INFO))
1676 col_append_fstr(pinfo->cinfo, COL_INFO,
1677 ", Duplicate Request %u",
1683 proto_tree_add_uint_hidden(tree, hf_mgcp_dup, tvb, 0,0, mi->transid);
1684 item = proto_tree_add_uint(tree, hf_mgcp_req_dup, tvb, 0,0, mi->transid);
1685 PROTO_ITEM_SET_GENERATED(item);
1691 /* Prepare the value data.
1692 "req_num" and "rsp_num" are frame numbers;
1693 frame numbers are 1-origin, so we use 0
1694 to mean "we don't yet know in which frame
1695 the reply for this call appears". */
1696 new_mgcp_call_key = g_mem_chunk_alloc(mgcp_call_info_key_chunk);
1697 *new_mgcp_call_key = mgcp_call_key;
1698 mgcp_call = g_mem_chunk_alloc(mgcp_call_info_value_chunk);
1699 mgcp_call->req_num = pinfo->fd->num;
1700 mgcp_call->rsp_num = 0;
1701 mgcp_call->transid = mi->transid;
1702 mgcp_call->responded = FALSE;
1703 mgcp_call->req_time=pinfo->fd->abs_ts;
1704 strcpy(mgcp_call->code,mi->code);
1707 g_hash_table_insert(mgcp_calls, new_mgcp_call_key, mgcp_call);
1709 if (mgcp_call && mgcp_call->rsp_num)
1711 proto_item* item = proto_tree_add_uint_format(tree, hf_mgcp_rsp_frame,
1712 tvb, 0, 0, mgcp_call->rsp_num,
1713 "The response to this request is in frame %u",
1714 mgcp_call->rsp_num);
1715 PROTO_ITEM_SET_GENERATED(item);
1722 mi->mgcp_type = mgcp_type;
1725 mi->req_time.secs=mgcp_call->req_time.secs;
1726 mi->req_time.nsecs=mgcp_call->req_time.nsecs;
1730 tap_queue_packet(mgcp_tap, pinfo, mi);
1734 * dissect_mgcp_params - Dissects the parameters of an MGCP message.
1735 * Adds the appropriate headers fields to
1736 * tree for the dissection of the parameters
1737 * of an MGCP message.
1740 * tvb - The tvb containing the parameters of an MGCP message. This
1741 * tvb is presumed to ONLY contain the part of the MGCP
1742 * message which contains the MGCP parameters.
1743 * tree - The tree from which to hang the structured information parsed
1744 * from the parameters of the MGCP message.
1746 static void dissect_mgcp_params(tvbuff_t *tvb, proto_tree *tree)
1748 int linelen, tokenlen, *my_param;
1749 gint tvb_lineend,tvb_current_len, tvb_linebegin,tvb_len,old_lineend;
1750 gint tvb_tokenbegin;
1751 proto_tree *mgcp_param_ti, *mgcp_param_tree;
1753 tvb_len = tvb_length(tvb);
1755 tvb_current_len = tvb_length_remaining(tvb,tvb_linebegin);
1756 tvb_lineend = tvb_linebegin;
1760 mgcp_param_ti = proto_tree_add_item(tree, hf_mgcp_params, tvb,
1761 tvb_linebegin, tvb_len, FALSE);
1762 proto_item_set_text(mgcp_param_ti, "Parameters");
1763 mgcp_param_tree = proto_item_add_subtree(mgcp_param_ti, ett_mgcp_param);
1765 /* Parse the parameters */
1766 while (tvb_lineend < tvb_len)
1768 old_lineend = tvb_lineend;
1769 linelen = tvb_find_line_end(tvb, tvb_linebegin, -1,&tvb_lineend,FALSE);
1770 tvb_tokenbegin = tvb_parse_param(tvb, tvb_linebegin, linelen, &my_param);
1774 if (*my_param == hf_mgcp_param_connectionparam)
1776 tokenlen = tvb_find_line_end(tvb,tvb_tokenbegin,-1,&tvb_lineend,FALSE);
1777 dissect_mgcp_connectionparams(mgcp_param_tree, tvb, tvb_linebegin,
1778 tvb_tokenbegin - tvb_linebegin, tokenlen);
1781 if (*my_param == hf_mgcp_param_localconnoptions)
1783 tokenlen = tvb_find_line_end(tvb,tvb_tokenbegin,-1,&tvb_lineend,FALSE);
1784 dissect_mgcp_localconnectionoptions(mgcp_param_tree, tvb, tvb_linebegin,
1785 tvb_tokenbegin - tvb_linebegin, tokenlen);
1789 tokenlen = tvb_find_line_end(tvb,tvb_tokenbegin,-1,&tvb_lineend,FALSE);
1790 proto_tree_add_string(mgcp_param_tree,*my_param, tvb,
1791 tvb_linebegin, linelen,
1792 tvb_format_text(tvb,tvb_tokenbegin, tokenlen));
1796 tvb_linebegin = tvb_lineend;
1797 /* Its a infinite loop if we didn't advance (or went backwards) */
1798 if (old_lineend >= tvb_lineend)
1800 THROW(ReportedBoundsError);
1806 /* Dissect the connection params */
1808 dissect_mgcp_connectionparams(proto_tree *parent_tree, tvbuff_t *tvb, gint offset, gint param_type_len, gint param_val_len)
1810 proto_tree *tree = parent_tree;
1811 proto_item *item = NULL;
1813 gchar *tokenline = NULL;
1814 gchar **tokens = NULL;
1815 gchar **typval = NULL;
1823 item = proto_tree_add_item(parent_tree, hf_mgcp_param_connectionparam, tvb, offset, param_type_len+param_val_len, FALSE);
1824 tree = proto_item_add_subtree(item, ett_mgcp_param_connectionparam);
1828 offset += param_type_len; /* skip the P: */
1829 tokenline = tvb_get_ephemeral_string(tvb, offset, param_val_len);
1831 /* Split into type=value pairs separated by comma */
1832 tokens = ep_strsplit(tokenline, ",", -1);
1834 for (i = 0; tokens[i] != NULL; i++)
1836 tokenlen = strlen(tokens[i]);
1837 typval = ep_strsplit(tokens[i], "=", 2);
1838 if ((typval[0] != NULL) && (typval[1] != NULL))
1840 if (!strcasecmp(g_strstrip(typval[0]), "PS"))
1842 hf_uint = hf_mgcp_param_connectionparam_ps;
1844 else if (!strcasecmp(g_strstrip(typval[0]), "OS"))
1846 hf_uint = hf_mgcp_param_connectionparam_os;
1848 else if (!strcasecmp(g_strstrip(typval[0]), "PR"))
1850 hf_uint = hf_mgcp_param_connectionparam_pr;
1852 else if (!strcasecmp(g_strstrip(typval[0]), "OR"))
1854 hf_uint = hf_mgcp_param_connectionparam_or;
1856 else if (!strcasecmp(g_strstrip(typval[0]), "PL"))
1858 hf_uint = hf_mgcp_param_connectionparam_pl;
1860 else if (!strcasecmp(g_strstrip(typval[0]), "JI"))
1862 hf_uint = hf_mgcp_param_connectionparam_ji;
1864 else if (!strcasecmp(g_strstrip(typval[0]), "LA"))
1866 hf_uint = hf_mgcp_param_connectionparam_la;
1868 else if (!strcasecmp(g_strstrip(typval[0]), "PC/RPS"))
1870 hf_uint = hf_mgcp_param_connectionparam_pcrps;
1871 } else if (!strcasecmp(g_strstrip(typval[0]), "PC/ROS"))
1873 hf_uint = hf_mgcp_param_connectionparam_pcros;
1875 else if (!strcasecmp(g_strstrip(typval[0]), "PC/RPL"))
1877 hf_uint = hf_mgcp_param_connectionparam_pcrpl;
1879 else if (!strcasecmp(g_strstrip(typval[0]), "PC/RJI"))
1881 hf_uint = hf_mgcp_param_connectionparam_pcrji;
1883 else if (!strncasecmp(g_strstrip(typval[0]), "X-", 2))
1885 hf_string = hf_mgcp_param_connectionparam_x;
1897 proto_tree_add_uint(tree, hf_uint, tvb, offset, tokenlen, atol(typval[1]));
1899 else if (hf_string != -1)
1901 proto_tree_add_string(tree, hf_string, tvb, offset, tokenlen, g_strstrip(typval[1]));
1905 proto_tree_add_text(tree, tvb, offset, tokenlen, "Unknown parameter: %s", tokens[i]);
1911 proto_tree_add_text(tree, tvb, offset, tokenlen, "Malformed parameter: %s", tokens[i]);
1913 offset += tokenlen + 1; /* 1 extra for the delimiter */
1918 /* Dissect the local connection option */
1920 dissect_mgcp_localconnectionoptions(proto_tree *parent_tree, tvbuff_t *tvb, gint offset, gint param_type_len, gint param_val_len)
1922 proto_tree *tree = parent_tree;
1923 proto_item *item = NULL;
1925 gchar *tokenline = NULL;
1926 gchar **tokens = NULL;
1927 gchar **typval = NULL;
1935 item = proto_tree_add_item(parent_tree, hf_mgcp_param_localconnoptions, tvb, offset, param_type_len+param_val_len, FALSE);
1936 tree = proto_item_add_subtree(item, ett_mgcp_param_localconnectionoptions);
1940 offset += param_type_len; /* skip the L: */
1941 tokenline = tvb_get_ephemeral_string(tvb, offset, param_val_len);
1943 /* Split into type=value pairs separated by comma */
1944 tokens = ep_strsplit(tokenline, ",", -1);
1945 for (i = 0; tokens[i] != NULL; i++)
1950 tokenlen = strlen(tokens[i]);
1951 typval = ep_strsplit(tokens[i], ":", 2);
1952 if ((typval[0] != NULL) && (typval[1] != NULL))
1954 if (!strcasecmp(g_strstrip(typval[0]), "p"))
1956 hf_uint = hf_mgcp_param_localconnoptions_p;
1958 else if (!strcasecmp(g_strstrip(typval[0]), "a"))
1960 hf_string = hf_mgcp_param_localconnoptions_a;
1962 else if (!strcasecmp(g_strstrip(typval[0]), "s"))
1964 hf_string = hf_mgcp_param_localconnoptions_s;
1966 else if (!strcasecmp(g_strstrip(typval[0]), "e"))
1968 hf_string = hf_mgcp_param_localconnoptions_e;
1970 else if (!strcasecmp(g_strstrip(typval[0]), "sc-rtp"))
1972 hf_string = hf_mgcp_param_localconnoptions_scrtp;
1974 else if (!strcasecmp(g_strstrip(typval[0]), "sc-rtcp"))
1976 hf_string = hf_mgcp_param_localconnoptions_scrtcp;
1978 else if (!strcasecmp(g_strstrip(typval[0]), "b"))
1980 hf_string = hf_mgcp_param_localconnoptions_b;
1982 else if (!strcasecmp(g_strstrip(typval[0]), "es-ccd"))
1984 hf_string = hf_mgcp_param_localconnoptions_esccd;
1986 else if (!strcasecmp(g_strstrip(typval[0]), "es-cci"))
1988 hf_string = hf_mgcp_param_localconnoptions_escci;
1990 else if (!strcasecmp(g_strstrip(typval[0]), "dq-gi"))
1992 hf_string = hf_mgcp_param_localconnoptions_dqgi;
1994 else if (!strcasecmp(g_strstrip(typval[0]), "dq-rd"))
1996 hf_string = hf_mgcp_param_localconnoptions_dqrd;
1998 else if (!strcasecmp(g_strstrip(typval[0]), "dq-ri"))
2000 hf_string = hf_mgcp_param_localconnoptions_dqri;
2002 else if (!strcasecmp(g_strstrip(typval[0]), "dq-rr"))
2004 hf_string = hf_mgcp_param_localconnoptions_dqrr;
2006 else if (!strcasecmp(g_strstrip(typval[0]), "k"))
2008 hf_string = hf_mgcp_param_localconnoptions_k;
2010 else if (!strcasecmp(g_strstrip(typval[0]), "gc"))
2012 hf_uint = hf_mgcp_param_localconnoptions_gc;
2014 else if (!strcasecmp(g_strstrip(typval[0]), "fmtp"))
2016 hf_string = hf_mgcp_param_localconnoptions_fmtp;
2018 else if (!strcasecmp(g_strstrip(typval[0]), "nt"))
2020 hf_string = hf_mgcp_param_localconnoptions_nt;
2022 else if (!strcasecmp(g_strstrip(typval[0]), "o-fmtp"))
2024 hf_string = hf_mgcp_param_localconnoptions_ofmtp;
2026 else if (!strcasecmp(g_strstrip(typval[0]), "r"))
2028 hf_string = hf_mgcp_param_localconnoptions_r;
2030 else if (!strcasecmp(g_strstrip(typval[0]), "t"))
2032 hf_string = hf_mgcp_param_localconnoptions_t;
2034 else if (!strcasecmp(g_strstrip(typval[0]), "r-cnf"))
2036 hf_string = hf_mgcp_param_localconnoptions_rcnf;
2038 else if (!strcasecmp(g_strstrip(typval[0]), "r-dir"))
2040 hf_string = hf_mgcp_param_localconnoptions_rdir;
2042 else if (!strcasecmp(g_strstrip(typval[0]), "r-sh"))
2044 hf_string = hf_mgcp_param_localconnoptions_rsh;
2057 proto_tree_add_uint(tree, hf_uint, tvb, offset, tokenlen, atol(typval[1]));
2059 else if (hf_string != -1)
2061 proto_tree_add_string(tree, hf_string, tvb, offset, tokenlen, g_strstrip(typval[1]));
2065 proto_tree_add_text(tree, tvb, offset, tokenlen, "Unknown parameter: %s", tokens[i]);
2071 proto_tree_add_text(tree, tvb, offset, tokenlen, "Malformed parameter: %s", tokens[i]);
2073 offset += tokenlen + 1; /* 1 extra for the delimiter */
2080 * tvb_skip_wsp - Returns the position in tvb of the first non-whitespace
2081 * character following offset or offset + maxlength -1 whichever
2085 * tvb - The tvbuff in which we are skipping whitespace.
2086 * offset - The offset in tvb from which we begin trying to skip whitespace.
2087 * maxlength - The maximum distance from offset that we may try to skip
2090 * Returns: The position in tvb of the first non-whitespace
2091 * character following offset or offset + maxlength -1 whichever
2094 static gint tvb_skip_wsp(tvbuff_t* tvb, gint offset, gint maxlength)
2096 gint counter = offset;
2097 gint end = offset + maxlength,tvb_len;
2100 /* Get the length remaining */
2101 tvb_len = tvb_length(tvb);
2102 end = offset + maxlength;
2108 /* Skip past spaces and tabs until run out or meet something else */
2109 for (counter = offset;
2111 ((tempchar = tvb_get_guint8(tvb,counter)) == ' ' ||
2119 * tvb_find_null_line - Returns the length from offset to the first null
2120 * line found (a null line is a line that begins
2121 * with a CR or LF. The offset to the first character
2122 * after the null line is written into the gint pointed
2123 * to by next_offset.
2126 * tvb - The tvbuff in which we are looking for a null line.
2127 * offset - The offset in tvb at which we will begin looking for
2129 * len - The maximum distance from offset in tvb that we will look for
2130 * a null line. If it is -1 we will look to the end of the buffer.
2132 * next_offset - The location to write the offset of first character
2133 * FOLLOWING the null line.
2135 * Returns: The length from offset to the first character BEFORE
2138 static gint tvb_find_null_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset)
2140 gint tvb_lineend,tvb_current_len,tvb_linebegin,maxoffset;
2143 tvb_linebegin = offset;
2144 tvb_lineend = tvb_linebegin;
2146 /* Simple setup to allow for the traditional -1 search to the end of the tvbuff */
2149 tvb_current_len = len;
2153 tvb_current_len = tvb_length_remaining(tvb,offset);
2156 maxoffset = (tvb_current_len - 1) + offset;
2158 /* Loop around until we either find a line begining with a carriage return
2159 or newline character or until we hit the end of the tvbuff. */
2162 tvb_linebegin = tvb_lineend;
2163 tvb_current_len = tvb_length_remaining(tvb,tvb_linebegin);
2164 tvb_find_line_end(tvb, tvb_linebegin, tvb_current_len, &tvb_lineend,FALSE);
2165 tempchar = tvb_get_guint8(tvb,tvb_linebegin);
2166 } while (tempchar != '\r' && tempchar != '\n' && tvb_lineend <= maxoffset);
2169 *next_offset = tvb_lineend;
2171 if (tvb_lineend <= maxoffset)
2173 tvb_current_len = tvb_linebegin - offset;
2177 tvb_current_len = tvb_length_remaining(tvb,offset);
2180 return tvb_current_len;
2184 * tvb_find_dot_line - Returns the length from offset to the first line
2185 * containing only a dot (.) character. A line
2186 * containing only a dot is used to indicate a
2187 * separation between multiple MGCP messages
2188 * piggybacked in the same UDP packet.
2191 * tvb - The tvbuff in which we are looking for a dot line.
2192 * offset - The offset in tvb at which we will begin looking for
2194 * len - The maximum distance from offset in tvb that we will look for
2195 * a dot line. If it is -1 we will look to the end of the buffer.
2197 * next_offset - The location to write the offset of first character
2198 * FOLLOWING the dot line.
2200 * Returns: The length from offset to the first character BEFORE
2201 * the dot line or -1 if the character at offset is a .
2202 * followed by a newline or a carriage return.
2204 static gint tvb_find_dot_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset)
2206 gint tvb_current_offset, tvb_current_len, maxoffset,tvb_len;
2208 tvb_current_offset = offset;
2209 tvb_current_len = len;
2210 tvb_len = tvb_length(tvb);
2214 maxoffset = tvb_len - 1;
2218 maxoffset = (len - 1) + offset;
2220 tvb_current_offset = offset -1;
2224 tvb_current_offset = tvb_find_guint8(tvb, tvb_current_offset+1,
2225 tvb_current_len, '.');
2226 tvb_current_len = maxoffset - tvb_current_offset + 1;
2228 /* If we didn't find a . then break out of the loop */
2229 if (tvb_current_offset == -1)
2234 /* Do we have and characters following the . ? */
2235 if (tvb_current_offset < maxoffset)
2237 tempchar = tvb_get_guint8(tvb,tvb_current_offset+1);
2238 /* Are the characters that follow the dot a newline or carriage return ? */
2239 if (tempchar == '\r' || tempchar == '\n')
2241 /* Do we have any charaters that proceed the . ? */
2242 if (tvb_current_offset == 0)
2248 tempchar = tvb_get_guint8(tvb,tvb_current_offset-1);
2250 /* Are the characters that follow the dot a newline or a
2251 carriage return ? */
2252 if (tempchar == '\r' || tempchar == '\n')
2260 if (tvb_current_offset == maxoffset)
2262 if (tvb_current_offset == 0)
2268 tempchar = tvb_get_guint8(tvb,tvb_current_offset-1);
2269 if (tempchar == '\r' || tempchar == '\n')
2275 } while (tvb_current_offset < maxoffset);
2279 * So now we either have the tvb_current_offset of a . in a dot line
2280 * or a tvb_current_offset of -1
2282 if (tvb_current_offset == -1)
2284 tvb_current_offset = maxoffset +1;
2285 *next_offset = maxoffset + 1;
2289 tvb_find_line_end(tvb,tvb_current_offset,tvb_current_len,next_offset,FALSE);
2292 if (tvb_current_offset == offset)
2294 tvb_current_len = -1;
2298 tvb_current_len = tvb_current_offset - offset;
2301 return tvb_current_len;