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_req_dup_frame = -1;
140 static int hf_mgcp_rsp_dup = -1;
141 static int hf_mgcp_rsp_dup_frame = -1;
143 static const value_string mgcp_return_code_vals[] = {
144 {000, "Response Acknowledgement"},
145 {100, "The transaction is currently being executed. An actual completion message will follow on later."},
146 {101, "The transaction has been queued for execution. An actual completion message will follow later."},
147 {200, "The requested transaction was executed normally."},
148 {250, "The connection was deleted."},
149 {400, "The transaction could not be executed, due to a transient error."},
150 {401, "The phone is already off hook"},
151 {402, "The phone is already on hook"},
152 {403, "The transaction could not be executed, because the endpoint does not have sufficient resources at this time"},
153 {404, "Insufficient bandwidth at this time"},
154 {405, "The transaction could not be executed, because the endpoint is \"restarting\"."},
155 {406, "Transaction time-out. The transaction did not complete in a reasonable period of time and has been aborted."},
156 {407, "Transaction aborted. The transaction was aborted by some external action, e.g., a ModifyConnection command aborted by a DeleteConnection command."},
157 {409, "The transaction could not be executed because of internal overload."},
158 {410, "No endpoint available. A valid \"any of\" wildcard was used, however there was no endpoint available to satisfy the request."},
159 {500, "The transaction could not be executed, because the endpoint is unknown."},
160 {501, "The transaction could not be executed, because the endpoint is not ready."},
161 {502, "The transaction could not be executed, because the endpoint does not have sufficient resources"},
162 {503, "\"All of\" wildcard too complicated."},
163 {504, "Unknown or unsupported command."},
164 {505, "Unsupported RemoteConnectionDescriptor."},
165 {506, "Unable to satisfy both LocalConnectionOptions and RemoteConnectionDescriptor."},
166 {507, "Unsupported functionality."},
167 {508, "Unknown or unsupported quarantine handling."},
168 {509, "Error in RemoteConnectionDescriptor."},
169 {510, "The transaction could not be executed, because a protocol error was detected."},
170 {511, "The transaction could not be executed, because the command contained an unrecognized extension."},
171 {512, "The transaction could not be executed, because the gateway is not equipped to detect one of the requested events."},
172 {513, "The transaction could not be executed, because the gateway is not equipped to generate one of the requested signals."},
173 {514, "The transaction could not be executed, because the gateway cannot send the specified announcement."},
174 {515, "The transaction refers to an incorrect connection-id (may have been already deleted)"},
175 {516, "The transaction refers to an unknown call-id."},
176 {517, "Unsupported or invalid mode."},
177 {518, "Unsupported or unknown package."},
178 {519, "Endpoint does not have a digit map."},
179 {520, "The transaction could not be executed, because the endpoint is 'restarting'."},
180 {521, "Endpoint redirected to another Call Agent."},
181 {522, "No such event or signal."},
182 {523, "Unknown action or illegal combination of actions"},
183 {524, "Internal inconsistency in LocalConnectionOptions"},
184 {525, "Unknown extension in LocalConnectionOptions"},
185 {526, "Insufficient bandwidth"},
186 {527, "Missing RemoteConnectionDescriptor"},
187 {528, "Incompatible protocol version"},
188 {529, "Internal hardware failure"},
189 {530, "CAS signaling protocol error."},
190 {531, "failure of a grouping of trunks (e.g. facility failure)."},
191 {532, "Unsupported value(s) in LocalConnectionOptions."},
192 {533, "Response too large."},
193 {534, "Codec negotiation failure."},
194 {535, "Packetization period not supported"},
195 {536, "Unknown or unsupported RestartMethod"},
196 {537, "Unknown or unsupported digit map extension"},
197 {538, "Event/signal parameter error (e.g., missing, erroneous, unsupported, unknown, etc.)"},
198 {539, "Invalid or unsupported command parameter."},
199 {540, "Per endpoint connection limit exceeded."},
200 {541, "Invalid or unsupported LocalConnectionOptions"},
204 /* TODO: add/use when tested/have capture to test with */
206 static const value_string mgcp_reason_code_vals[] = {
207 {0, "Endpoint state is normal"},
208 {900, "Endpoint malfunctioning."},
209 {901, "Endpoint taken out-of-service."},
210 {902, "Loss of lower layer connectivity (e.g., downstream sync)."},
211 {903, "QoS resource reservation was lost."},
212 {904, "Manual intervention."},
213 {905, "Facility failure (e.g., DS-0 failure)."},
220 * Define the trees for mgcp
221 * We need one for MGCP itself, one for the MGCP paramters and one
222 * for each of the dissected parameters
224 static int ett_mgcp = -1;
225 static int ett_mgcp_param = -1;
226 static int ett_mgcp_param_connectionparam = -1;
227 static int ett_mgcp_param_localconnectionoptions = -1;
230 * Define the tap for mgcp
232 static int mgcp_tap = -1;
235 * Here are the global variables associated with
236 * the various user definable characteristics of the dissection
238 * MGCP has two kinds of "agents", gateways and callagents. Callagents
239 * control gateways in a master/slave sort of arrangement. Since gateways
240 * and callagents have different well known ports and could both
241 * operate under either udp or tcp we have rather a lot of port info to
244 * global_mgcp_raw_text determines whether we are going to display
245 * the raw text of the mgcp message, much like the HTTP dissector does.
248 static guint global_mgcp_gateway_tcp_port = TCP_PORT_MGCP_GATEWAY;
249 static guint global_mgcp_gateway_udp_port = UDP_PORT_MGCP_GATEWAY;
250 static guint global_mgcp_callagent_tcp_port = TCP_PORT_MGCP_CALLAGENT;
251 static guint global_mgcp_callagent_udp_port = UDP_PORT_MGCP_CALLAGENT;
252 static gboolean global_mgcp_raw_text = FALSE;
253 static gboolean global_mgcp_message_count = FALSE;
256 * Variables to allow for proper deletion of dissector registration when
257 * the user changes port from the gui.
259 static int gateway_tcp_port = 0;
260 static int gateway_udp_port = 0;
261 static int callagent_tcp_port = 0;
262 static int callagent_udp_port = 0;
264 /* Some basic utility functions that are specific to this dissector */
265 static gboolean is_mgcp_verb(tvbuff_t *tvb, gint offset, gint maxlength, const gchar **verb_name);
266 static gboolean is_mgcp_rspcode(tvbuff_t *tvb, gint offset, gint maxlength);
267 static gint tvb_parse_param(tvbuff_t *tvb, gint offset, gint maxlength, int** hf);
270 * The various functions that either dissect some
271 * subpart of MGCP. These aren't really proto dissectors but they
272 * are written in the same style.
274 static void dissect_mgcp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
275 proto_tree *mgcp_tree, proto_tree *ti);
276 static void dissect_mgcp_firstline(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
277 static void dissect_mgcp_params(tvbuff_t *tvb, proto_tree *tree);
278 static void dissect_mgcp_connectionparams(proto_tree *parent_tree, tvbuff_t *tvb,
279 gint offset, gint param_type_len,
281 static void dissect_mgcp_localconnectionoptions(proto_tree *parent_tree, tvbuff_t *tvb,
282 gint offset, gint param_type_len,
286 static void mgcp_raw_text_add(tvbuff_t *tvb, proto_tree *tree);
289 * Some functions which should be moved to a library
290 * as I think that people may find them of general usefulness.
292 static gint tvb_skip_wsp(tvbuff_t* tvb, gint offset, gint maxlength);
293 static gint tvb_find_null_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset);
294 static gint tvb_find_dot_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset);
295 static gboolean is_rfc2234_alpha(guint8 c);
297 static dissector_handle_t sdp_handle;
298 static dissector_handle_t mgcp_handle;
300 dissect_asciitpkt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
301 dissector_handle_t subdissector_handle);
302 extern guint16 is_asciitpkt(tvbuff_t *tvb);
305 * Init Hash table stuff
308 typedef struct _mgcp_call_info_key
311 conversation_t *conversation;
312 } mgcp_call_info_key;
314 static GMemChunk *mgcp_call_info_key_chunk;
315 static GMemChunk *mgcp_call_info_value_chunk;
316 static GHashTable *mgcp_calls;
319 static gint mgcp_call_equal(gconstpointer k1, gconstpointer k2)
321 const mgcp_call_info_key* key1 = (const mgcp_call_info_key*) k1;
322 const mgcp_call_info_key* key2 = (const mgcp_call_info_key*) k2;
324 return (key1->transid == key2->transid &&
325 key1->conversation == key2->conversation);
328 /* Calculate a hash key */
329 static guint mgcp_call_hash(gconstpointer k)
331 const mgcp_call_info_key* key = (const mgcp_call_info_key*) k;
333 return key->transid + key->conversation->index;
337 /************************************************************************
338 * dissect_mgcp - The dissector for the Media Gateway Control Protocol
339 ************************************************************************/
340 static void dissect_mgcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
343 guint32 num_messages;
344 gint tvb_sectionend,tvb_sectionbegin, tvb_len, tvb_current_len;
345 proto_tree *mgcp_tree, *ti;
346 const gchar *verb_name = "";
348 /* Initialize variables */
350 tvb_sectionbegin = tvb_sectionend;
352 tvb_len = tvb_length(tvb);
353 tvb_current_len = tvb_len;
359 * Set the columns now, so that they'll be set correctly if we throw
360 * an exception. We can set them later as well....
362 if (check_col(pinfo->cinfo, COL_PROTOCOL))
363 col_add_str(pinfo->cinfo, COL_PROTOCOL, "MGCP");
364 if (check_col(pinfo->cinfo, COL_INFO))
365 col_clear(pinfo->cinfo, COL_INFO);
368 * Check to see whether we're really dealing with MGCP by looking
369 * for a valid MGCP verb or response code. This isn't infallible,
370 * but its cheap and its better than nothing.
372 if (is_mgcp_verb(tvb,0,tvb_len, &verb_name) || is_mgcp_rspcode(tvb,0,tvb_len))
375 * Loop through however many mgcp messages may be stuck in
376 * this packet using piggybacking
383 /* Create our mgcp subtree */
384 ti = proto_tree_add_item(tree,proto_mgcp,tvb,0,0, FALSE);
385 mgcp_tree = proto_item_add_subtree(ti, ett_mgcp);
388 sectionlen = tvb_find_dot_line(tvb, tvb_sectionbegin, -1, &tvb_sectionend);
389 if (sectionlen != -1)
391 dissect_mgcp_message(tvb_new_subset(tvb, tvb_sectionbegin,
393 pinfo, tree, mgcp_tree,ti);
394 tvb_sectionbegin = tvb_sectionend;
400 } while (tvb_sectionend < tvb_len);
404 proto_tree_add_uint_hidden(mgcp_tree, hf_mgcp_messagecount, tvb,
405 0 ,0 , num_messages);
409 * Add our column information after dissecting SDP
410 * in order to prevent the column info changing to reflect the SDP
411 * (when showing message count)
413 tvb_sectionbegin = 0;
414 if (check_col(pinfo->cinfo, COL_PROTOCOL))
416 if (global_mgcp_message_count == TRUE )
418 if (num_messages > 1)
420 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "MGCP (%i messages)",num_messages);
424 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "MGCP (%i message)",num_messages);
429 if (check_col(pinfo->cinfo, COL_INFO))
431 sectionlen = tvb_find_line_end(tvb, tvb_sectionbegin,-1,
432 &tvb_sectionend,FALSE);
433 col_prepend_fstr(pinfo->cinfo, COL_INFO, "%s",
434 tvb_format_text(tvb, tvb_sectionbegin, sectionlen));
438 /************************************************************************
439 * dissect_tpkt_mgcp - The dissector for the ASCII TPKT Media Gateway Control Protocol
440 ************************************************************************/
441 static void dissect_tpkt_mgcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
445 /* Check whether this looks like a ASCII TPKT-encapsulated
448 ascii_tpkt = is_asciitpkt(tvb);
450 if (ascii_tpkt == 0 )
453 * It's not a ASCII TPKT packet
456 dissect_mgcp(tvb, pinfo, tree);
461 * Dissect ASCII TPKT header
463 dissect_asciitpkt(tvb, pinfo, tree, mgcp_handle);
467 #define MAX_MGCP_MESSAGES_IN_PACKET 5
468 static mgcp_info_t pi_arr[MAX_MGCP_MESSAGES_IN_PACKET];
469 static int pi_current = 0;
470 static mgcp_info_t *mi;
472 /* Dissect an individual MGCP message */
473 static void dissect_mgcp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
474 proto_tree *mgcp_tree, proto_tree *ti)
476 /* Declare variables */
478 gint tvb_sectionend,tvb_sectionbegin, tvb_len, tvb_current_len;
480 const gchar *verb_name = "";
482 /* Initialise stat info for passing to tap */
484 if (pi_current == MAX_MGCP_MESSAGES_IN_PACKET)
486 /* Overwrite info in first struct if run out of space... */
489 mi = &pi_arr[pi_current];
492 mi->mgcp_type = MGCP_OTHERS;
495 mi->req_time.secs = 0;
496 mi->req_time.nsecs = 0;
497 mi->is_duplicate = FALSE;
498 mi->request_available = FALSE;
500 mi->endpointId = NULL;
501 mi->observedEvents = NULL;
503 mi->signalReq = NULL;
504 mi->hasDigitMap = FALSE;
506 /* Initialize variables */
508 tvb_sectionbegin = tvb_sectionend;
510 tvb_len = tvb_length(tvb);
511 tvb_current_len = tvb_len;
514 * Check to see whether we're really dealing with MGCP by looking
515 * for a valid MGCP verb or response code. This isn't infallible,
516 * but its cheap and its better than nothing.
518 if (is_mgcp_verb(tvb,0,tvb_len,&verb_name) || is_mgcp_rspcode(tvb,0,tvb_len))
520 /* dissect first line */
521 tvb_sectionbegin = 0;
522 tvb_current_len = tvb_len;
523 tvb_sectionend = tvb_sectionbegin;
524 sectionlen = tvb_find_line_end(tvb,0,-1,&tvb_sectionend,FALSE);
527 dissect_mgcp_firstline(tvb_new_subset(tvb, tvb_sectionbegin,
528 sectionlen,-1), pinfo,
531 tvb_sectionbegin = tvb_sectionend;
534 if (tvb_sectionbegin < tvb_len)
536 sectionlen = tvb_find_null_line(tvb, tvb_sectionbegin, -1,
540 dissect_mgcp_params(tvb_new_subset(tvb, tvb_sectionbegin, sectionlen, -1),
542 tvb_sectionbegin = tvb_sectionend;
546 /* Set the mgcp payload length correctly so we don't include any
548 sectionlen = tvb_sectionend;
549 proto_item_set_len(ti,sectionlen);
551 /* Display the raw text of the mgcp message if desired */
553 /* Do we want to display the raw text of our MGCP packet? */
554 if (global_mgcp_raw_text)
557 mgcp_raw_text_add(tvb, mgcp_tree);
560 /* Dissect sdp payload */
561 if (tvb_sectionend < tvb_len)
563 next_tvb = tvb_new_subset(tvb, tvb_sectionend, -1, -1);
564 call_dissector(sdp_handle, next_tvb, pinfo, tree);
571 * Add the raw text of the message to the dissect tree if appropriate
572 * preferences are specified.
574 static void mgcp_raw_text_add(tvbuff_t *tvb, proto_tree *tree)
576 gint tvb_linebegin,tvb_lineend,tvb_len,linelen;
579 tvb_len = tvb_length(tvb);
583 tvb_find_line_end(tvb,tvb_linebegin,-1,&tvb_lineend,FALSE);
584 linelen = tvb_lineend - tvb_linebegin;
585 proto_tree_add_text(tree, tvb, tvb_linebegin, linelen, "%s",
586 tvb_format_text(tvb, tvb_linebegin, linelen));
587 tvb_linebegin = tvb_lineend;
588 } while (tvb_lineend < tvb_len);
591 /* Discard and init any state we've saved */
592 static void mgcp_init_protocol(void)
594 if (mgcp_calls != NULL)
596 g_hash_table_destroy(mgcp_calls);
599 if (mgcp_call_info_key_chunk != NULL)
601 g_mem_chunk_destroy(mgcp_call_info_key_chunk);
602 mgcp_call_info_key_chunk = NULL;
604 if (mgcp_call_info_value_chunk != NULL)
606 g_mem_chunk_destroy(mgcp_call_info_value_chunk);
607 mgcp_call_info_value_chunk = NULL;
610 mgcp_calls = g_hash_table_new(mgcp_call_hash, mgcp_call_equal);
611 mgcp_call_info_key_chunk = g_mem_chunk_new("call_info_key_chunk",
612 sizeof(mgcp_call_info_key),
613 200 * sizeof(mgcp_call_info_key),
615 mgcp_call_info_value_chunk = g_mem_chunk_new("call_info_value_chunk",
617 200 * sizeof(mgcp_call_t),
621 /* Register all the bits needed with the filtering engine */
622 void proto_register_mgcp(void)
624 static hf_register_info hf[] =
627 { "Request", "mgcp.req", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
628 "True if MGCP request", HFILL }},
630 { "Response", "mgcp.rsp", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
631 "TRUE if MGCP response", HFILL }},
632 { &hf_mgcp_req_frame,
633 { "Request Frame", "mgcp.reqframe", FT_FRAMENUM, BASE_NONE, NULL, 0,
634 "Request Frame", HFILL }},
635 { &hf_mgcp_rsp_frame,
636 { "Response Frame", "mgcp.rspframe", FT_FRAMENUM, BASE_NONE, NULL, 0,
637 "Response Frame", HFILL }},
639 { "Time from request", "mgcp.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0,
640 "Timedelta between Request and Response", HFILL }},
642 { "Verb", "mgcp.req.verb", FT_STRING, BASE_DEC, NULL, 0x0,
643 "Name of the verb", HFILL }},
644 { &hf_mgcp_req_endpoint,
645 { "Endpoint", "mgcp.req.endpoint", FT_STRING, BASE_DEC, NULL, 0x0,
646 "Endpoint referenced by the message", HFILL }},
648 { "Transaction ID", "mgcp.transid", FT_STRING, BASE_DEC, NULL, 0x0,
649 "Transaction ID of this message", HFILL }},
651 { "Version", "mgcp.version", FT_STRING, BASE_DEC, NULL, 0x0,
652 "MGCP Version", HFILL }},
653 { &hf_mgcp_rsp_rspcode,
654 { "Response Code", "mgcp.rsp.rspcode", FT_UINT32, BASE_DEC, VALS(mgcp_return_code_vals), 0x0,
655 "Response Code", HFILL }},
656 { &hf_mgcp_rsp_rspstring,
657 { "Response String", "mgcp.rsp.rspstring", FT_STRING, BASE_DEC, NULL, 0x0,
658 "Response String", HFILL }},
660 { "Parameters", "mgcp.params", FT_NONE, 0, NULL, 0x0,
661 "MGCP parameters", HFILL }},
662 { &hf_mgcp_param_rspack,
663 { "ResponseAck (K)", "mgcp.param.rspack", FT_STRING, BASE_DEC, NULL, 0x0,
664 "Response Ack", HFILL }},
665 { &hf_mgcp_param_bearerinfo,
666 { "BearerInformation (B)", "mgcp.param.bearerinfo", FT_STRING, BASE_DEC, NULL, 0x0,
667 "Bearer Information", HFILL }},
668 { &hf_mgcp_param_callid,
669 { "CallId (C)", "mgcp.param.callid", FT_STRING, BASE_DEC, NULL, 0x0,
671 { &hf_mgcp_param_connectionid,
672 {"ConnectionIdentifier (I)", "mgcp.param.connectionid", FT_STRING, BASE_DEC, NULL, 0x0,
673 "Connection Identifier", HFILL }},
674 { &hf_mgcp_param_secondconnectionid,
675 { "SecondConnectionID (I2)", "mgcp.param.secondconnectionid", FT_STRING, BASE_DEC, NULL, 0x0,
676 "Second Connection Identifier", HFILL }},
677 { &hf_mgcp_param_notifiedentity,
678 { "NotifiedEntity (N)", "mgcp.param.notifiedentity", FT_STRING, BASE_DEC, NULL, 0x0,
679 "Notified Entity", HFILL }},
680 { &hf_mgcp_param_requestid,
681 { "RequestIdentifier (X)", "mgcp.param.requestid", FT_STRING, BASE_DEC, NULL, 0x0,
682 "Request Identifier", HFILL }},
683 { &hf_mgcp_param_localconnoptions,
684 { "LocalConnectionOptions (L)", "mgcp.param.localconnectionoptions", FT_STRING, BASE_DEC, NULL, 0x0,
685 "Local Connection Options", HFILL }},
686 { &hf_mgcp_param_localconnoptions_p,
687 { "Packetization period (p)", "mgcp.param.localconnectionoptions.p", FT_UINT32, BASE_DEC, NULL, 0x0,
688 "Packetization period", HFILL }},
689 { &hf_mgcp_param_localconnoptions_a,
690 { "Codecs (a)", "mgcp.param.localconnectionoptions.a", FT_STRING, BASE_DEC, NULL, 0x0,
692 { &hf_mgcp_param_localconnoptions_s,
693 { "Silence Suppression (s)", "mgcp.param.localconnectionoptions.s", FT_STRING, BASE_DEC, NULL, 0x0,
694 "Silence Suppression", HFILL }},
695 { &hf_mgcp_param_localconnoptions_e,
696 { "Echo Cancellation (e)", "mgcp.param.localconnectionoptions.e", FT_STRING, BASE_DEC, NULL, 0x0,
697 "Echo Cancellation", HFILL }},
698 { &hf_mgcp_param_localconnoptions_scrtp,
699 { "RTP ciphersuite (sc-rtp)", "mgcp.param.localconnectionoptions.scrtp", FT_STRING, BASE_DEC, NULL, 0x0,
700 "RTP ciphersuite", HFILL }},
701 { &hf_mgcp_param_localconnoptions_scrtcp,
702 { "RTCP ciphersuite (sc-rtcp)", "mgcp.param.localconnectionoptions.scrtcp", FT_STRING, BASE_DEC, NULL, 0x0,
703 "RTCP ciphersuite", HFILL }},
704 { &hf_mgcp_param_localconnoptions_b,
705 { "Bandwidth (b)", "mgcp.param.localconnectionoptions.b", FT_STRING, BASE_DEC, NULL, 0x0,
706 "Bandwidth", HFILL }},
707 { &hf_mgcp_param_localconnoptions_esccd,
708 { "Content Destination (es-ccd)", "mgcp.param.localconnectionoptions.esccd", FT_STRING, BASE_DEC, NULL, 0x0,
709 "Content Destination", HFILL }},
710 { &hf_mgcp_param_localconnoptions_escci,
711 { "Content Identifier (es-cci)", "mgcp.param.localconnectionoptions.escci", FT_STRING, BASE_DEC, NULL, 0x0,
712 "Content Identifier", HFILL }},
713 { &hf_mgcp_param_localconnoptions_dqgi,
714 { "D-QoS GateID (dq-gi)", "mgcp.param.localconnectionoptions.dqgi", FT_STRING, BASE_DEC, NULL, 0x0,
715 "D-QoS GateID", HFILL }},
716 { &hf_mgcp_param_localconnoptions_dqrd,
717 { "D-QoS Reserve Destination (dq-rd)", "mgcp.param.localconnectionoptions.dqrd", FT_STRING, BASE_DEC, NULL, 0x0,
718 "D-QoS Reserve Destination", HFILL }},
719 { &hf_mgcp_param_localconnoptions_dqri,
720 { "D-QoS Resource ID (dq-ri)", "mgcp.param.localconnectionoptions.dqri", FT_STRING, BASE_DEC, NULL, 0x0,
721 "D-QoS Resource ID", HFILL }},
722 { &hf_mgcp_param_localconnoptions_dqrr,
723 { "D-QoS Resource Reservation (dq-rr)", "mgcp.param.localconnectionoptions.dqrr", FT_STRING, BASE_DEC, NULL, 0x0,
724 "D-QoS Resource Reservation", HFILL }},
725 { &hf_mgcp_param_localconnoptions_k,
726 { "Encryption Key (k)", "mgcp.param.localconnectionoptions.k", FT_STRING, BASE_DEC, NULL, 0x0,
727 "Encryption Key", HFILL }},
728 { &hf_mgcp_param_localconnoptions_gc,
729 { "Gain Control (gc)", "mgcp.param.localconnectionoptions.gc", FT_UINT32, BASE_DEC, NULL, 0x0,
730 "Gain Control", HFILL }},
731 { &hf_mgcp_param_localconnoptions_fmtp,
732 { "Media Format (fmtp)", "mgcp.param.localconnectionoptions.fmtp", FT_STRING, BASE_DEC, NULL, 0x0,
733 "Media Format", HFILL }},
734 { &hf_mgcp_param_localconnoptions_nt,
735 { "Network Type (nt)", "mgcp.param.localconnectionoptions.nt", FT_STRING, BASE_DEC, NULL, 0x0,
736 "Network Type", HFILL }},
737 { &hf_mgcp_param_localconnoptions_ofmtp,
738 { "Optional Media Format (o-fmtp)", "mgcp.param.localconnectionoptions.ofmtp", FT_STRING, BASE_DEC, NULL, 0x0,
739 "Optional Media Format", HFILL }},
740 { &hf_mgcp_param_localconnoptions_r,
741 { "Resource Reservation (r)", "mgcp.param.localconnectionoptions.r", FT_STRING, BASE_DEC, NULL, 0x0,
742 "Resource Reservation", HFILL }},
743 { &hf_mgcp_param_localconnoptions_t,
744 { "Type of Service (r)", "mgcp.param.localconnectionoptions.t", FT_STRING, BASE_DEC, NULL, 0x0,
745 "Type of Service", HFILL }},
746 { &hf_mgcp_param_localconnoptions_rcnf,
747 { "Reservation Confirmation (r-cnf)", "mgcp.param.localconnectionoptions.rcnf", FT_STRING, BASE_DEC, NULL, 0x0,
748 "Reservation Confirmation", HFILL }},
749 { &hf_mgcp_param_localconnoptions_rdir,
750 { "Reservation Direction (r-dir)", "mgcp.param.localconnectionoptions.rdir", FT_STRING, BASE_DEC, NULL, 0x0,
751 "Reservation Direction", HFILL }},
752 { &hf_mgcp_param_localconnoptions_rsh,
753 { "Resource Sharing (r-sh)", "mgcp.param.localconnectionoptions.rsh", FT_STRING, BASE_DEC, NULL, 0x0,
754 "Resource Sharing", HFILL }},
755 { &hf_mgcp_param_connectionmode,
756 { "ConnectionMode (M)", "mgcp.param.connectionmode", FT_STRING, BASE_DEC, NULL, 0x0,
757 "Connection Mode", HFILL }},
758 { &hf_mgcp_param_reqevents,
759 { "RequestedEvents (R)", "mgcp.param.reqevents", FT_STRING, BASE_DEC, NULL, 0x0,
760 "Requested Events", HFILL }},
761 { &hf_mgcp_param_signalreq,
762 { "SignalRequests (S)", "mgcp.param.signalreq", FT_STRING, BASE_DEC, NULL, 0x0,
763 "Signal Request", HFILL }},
764 { &hf_mgcp_param_restartmethod,
765 { "RestartMethod (RM)", "mgcp.param.restartmethod", FT_STRING, BASE_DEC, NULL, 0x0,
766 "Restart Method", HFILL }},
767 { &hf_mgcp_param_restartdelay,
768 { "RestartDelay (RD)", "mgcp.param.restartdelay", FT_STRING, BASE_DEC, NULL, 0x0,
769 "Restart Delay", HFILL }},
770 { &hf_mgcp_param_digitmap,
771 { "DigitMap (D)", "mgcp.param.digitmap", FT_STRING, BASE_DEC, NULL, 0x0,
772 "Digit Map", HFILL }},
773 { &hf_mgcp_param_observedevent,
774 { "ObservedEvents (O)", "mgcp.param.observedevents", FT_STRING, BASE_DEC, NULL, 0x0,
775 "Observed Events", HFILL }},
776 { &hf_mgcp_param_connectionparam,
777 { "ConnectionParameters (P)", "mgcp.param.connectionparam", FT_STRING, BASE_DEC, NULL, 0x0,
778 "Connection Parameters", HFILL }},
779 { &hf_mgcp_param_connectionparam_ps,
780 { "Packets sent (PS)", "mgcp.param.connectionparam.ps", FT_UINT32, BASE_DEC, NULL, 0x0,
781 "Packets sent (P:PS)", HFILL }},
782 { &hf_mgcp_param_connectionparam_os,
783 { "Octets sent (OS)", "mgcp.param.connectionparam.os", FT_UINT32, BASE_DEC, NULL, 0x0,
784 "Octets sent (P:OS)", HFILL }},
785 { &hf_mgcp_param_connectionparam_pr,
786 { "Packets received (PR)", "mgcp.param.connectionparam.pr", FT_UINT32, BASE_DEC, NULL, 0x0,
787 "Packets received (P:PR)", HFILL }},
788 { &hf_mgcp_param_connectionparam_or,
789 { "Octets received (OR)", "mgcp.param.connectionparam.or", FT_UINT32, BASE_DEC, NULL, 0x0,
790 "Octets received (P:OR)", HFILL }},
791 { &hf_mgcp_param_connectionparam_pl,
792 { "Packets lost (PL)", "mgcp.param.connectionparam.pl", FT_UINT32, BASE_DEC, NULL, 0x0,
793 "Packets lost (P:PL)", HFILL }},
794 { &hf_mgcp_param_connectionparam_ji,
795 { "Jitter (JI)", "mgcp.param.connectionparam.ji", FT_UINT32, BASE_DEC, NULL, 0x0,
796 "Average inter-packet arrival jitter in milliseconds (P:JI)", HFILL }},
797 { &hf_mgcp_param_connectionparam_la,
798 { "Latency (LA)", "mgcp.param.connectionparam.la", FT_UINT32, BASE_DEC, NULL, 0x0,
799 "Average latency in milliseconds (P:LA)", HFILL }},
800 { &hf_mgcp_param_connectionparam_pcrps,
801 { "Remote Packets sent (PC/RPS)", "mgcp.param.connectionparam.pcrps", FT_UINT32, BASE_DEC, NULL, 0x0,
802 "Remote Packets sent (P:PC/RPS)", HFILL }},
803 { &hf_mgcp_param_connectionparam_pcros,
804 { "Remote Octets sent (PC/ROS)", "mgcp.param.connectionparam.pcros", FT_UINT32, BASE_DEC, NULL, 0x0,
805 "Remote Octets sent (P:PC/ROS)", HFILL }},
806 { &hf_mgcp_param_connectionparam_pcrpl,
807 { "Remote Packets lost (PC/RPL)", "mgcp.param.connectionparam.pcrpl", FT_UINT32, BASE_DEC, NULL, 0x0,
808 "Remote Packets lost (P:PC/RPL)", HFILL }},
809 { &hf_mgcp_param_connectionparam_pcrji,
810 { "Remote Jitter (PC/RJI)", "mgcp.param.connectionparam.pcrji", FT_UINT32, BASE_DEC, NULL, 0x0,
811 "Remote Jitter (P:PC/RJI)", HFILL }},
812 { &hf_mgcp_param_connectionparam_x,
813 { "Vendor Extension", "mgcp.param.connectionparam.x", FT_STRING, BASE_DEC, NULL, 0x0,
814 "Vendor Extension (P:X-*)", HFILL }},
815 { &hf_mgcp_param_reasoncode,
816 { "ReasonCode (E)", "mgcp.param.reasoncode", FT_STRING, BASE_DEC, NULL, 0x0,
817 "Reason Code", HFILL }},
818 { &hf_mgcp_param_eventstates,
819 { "EventStates (ES)", "mgcp.param.eventstates", FT_STRING, BASE_DEC, NULL, 0x0,
820 "Event States", HFILL }},
821 { &hf_mgcp_param_specificendpoint,
822 { "SpecificEndpointID (Z)", "mgcp.param.specificendpointid", FT_STRING, BASE_DEC, NULL, 0x0,
823 "Specific Endpoint ID", HFILL }},
824 { &hf_mgcp_param_secondendpointid,
825 { "SecondEndpointID (Z2)", "mgcp.param.secondendpointid", FT_STRING, BASE_DEC, NULL, 0x0,
826 "Second Endpoing ID", HFILL }},
827 { &hf_mgcp_param_reqinfo,
828 { "RequestedInfo (F)", "mgcp.param.reqinfo", FT_STRING, BASE_DEC, NULL, 0x0,
829 "Requested Info", HFILL }},
830 { &hf_mgcp_param_quarantinehandling,
831 { "QuarantineHandling (Q)", "mgcp.param.quarantinehandling", FT_STRING, BASE_DEC, NULL, 0x0,
832 "Quarantine Handling", HFILL }},
833 { &hf_mgcp_param_detectedevents,
834 { "DetectedEvents (T)", "mgcp.param.detectedevents", FT_STRING, BASE_DEC, NULL, 0x0,
835 "Detected Events", HFILL }},
836 { &hf_mgcp_param_capabilities,
837 { "Capabilities (A)", "mgcp.param.capabilities", FT_STRING, BASE_DEC, NULL, 0x0,
838 "Capabilities", HFILL }},
839 { &hf_mgcp_param_maxmgcpdatagram,
840 {"MaxMGCPDatagram (MD)", "mgcp.param.maxmgcpdatagram", FT_STRING, BASE_DEC, NULL, 0x0,
841 "Maximum MGCP Datagram size", HFILL }},
842 { &hf_mgcp_param_packagelist,
843 {"PackageList (PL)", "mgcp.param.packagelist", FT_STRING, BASE_DEC, NULL, 0x0,
844 "Package List", HFILL }},
845 { &hf_mgcp_param_extension,
846 { "Extension Parameter (non-critical)", "mgcp.param.extension", FT_STRING, BASE_DEC, NULL, 0x0,
847 "Extension Parameter", HFILL }},
848 { &hf_mgcp_param_extension_critical,
849 { "Extension Parameter (critical)", "mgcp.param.extensioncritical", FT_STRING, BASE_DEC, NULL, 0x0,
850 "Critical Extension Parameter", HFILL }},
851 { &hf_mgcp_param_invalid,
852 { "Invalid Parameter", "mgcp.param.invalid", FT_STRING, BASE_DEC, NULL, 0x0,
853 "Invalid Parameter", HFILL }},
854 { &hf_mgcp_messagecount,
855 { "MGCP Message Count", "mgcp.messagecount", FT_UINT32, BASE_DEC, NULL, 0x0,
856 "Number of MGCP message in a packet", HFILL }},
858 { "Duplicate Message", "mgcp.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
859 "Duplicate Message", HFILL }},
861 { "Duplicate Request", "mgcp.req.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
862 "Duplicate Request", HFILL }},
863 { &hf_mgcp_req_dup_frame,
864 { "Original Request Frame", "mgcp.req.dup.frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
865 "Frame containing original request", HFILL }},
867 { "Duplicate Response", "mgcp.rsp.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
868 "Duplicate Response", HFILL }},
869 { &hf_mgcp_rsp_dup_frame,
870 { "Original Response Frame", "mgcp.rsp.dup.frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
871 "Frame containing original response", HFILL }},
878 &ett_mgcp_param_connectionparam,
879 &ett_mgcp_param_localconnectionoptions
882 module_t *mgcp_module;
884 /* Register protocol */
885 proto_mgcp = proto_register_protocol("Media Gateway Control Protocol", "MGCP", "mgcp");
886 proto_register_field_array(proto_mgcp, hf, array_length(hf));
887 proto_register_subtree_array(ett, array_length(ett));
888 register_init_routine(&mgcp_init_protocol);
890 register_dissector("mgcp", dissect_mgcp, proto_mgcp);
892 /* Register our configuration options */
893 mgcp_module = prefs_register_protocol(proto_mgcp, proto_reg_handoff_mgcp);
895 prefs_register_uint_preference(mgcp_module, "tcp.gateway_port",
896 "MGCP Gateway TCP Port",
897 "Set the UDP port for gateway messages "
898 "(if other than the default of 2427)",
899 10, &global_mgcp_gateway_tcp_port);
901 prefs_register_uint_preference(mgcp_module, "udp.gateway_port",
902 "MGCP Gateway UDP Port",
903 "Set the TCP port for gateway messages "
904 "(if other than the default of 2427)",
905 10, &global_mgcp_gateway_udp_port);
907 prefs_register_uint_preference(mgcp_module, "tcp.callagent_port",
908 "MGCP Callagent TCP Port",
909 "Set the TCP port for callagent messages "
910 "(if other than the default of 2727)",
911 10, &global_mgcp_callagent_tcp_port);
913 prefs_register_uint_preference(mgcp_module, "udp.callagent_port",
914 "MGCP Callagent UDP Port",
915 "Set the UDP port for callagent messages "
916 "(if other than the default of 2727)",
917 10, &global_mgcp_callagent_udp_port);
920 prefs_register_bool_preference(mgcp_module, "display_raw_text",
921 "Display raw text for MGCP message",
922 "Specifies that the raw text of the "
923 "MGCP message should be displayed "
924 "instead of (or in addition to) the "
926 &global_mgcp_raw_text);
928 prefs_register_obsolete_preference(mgcp_module, "display_dissect_tree");
930 prefs_register_bool_preference(mgcp_module, "display_mgcp_message_count",
931 "Display the number of MGCP messages",
932 "Display the number of MGCP messages "
933 "found in a packet in the protocol column.",
934 &global_mgcp_message_count);
936 mgcp_tap = register_tap("mgcp");
939 /* The registration hand-off routine */
940 void proto_reg_handoff_mgcp(void)
942 static int mgcp_prefs_initialized = FALSE;
943 static dissector_handle_t mgcp_tpkt_handle;
944 /* Get a handle for the SDP dissector. */
945 sdp_handle = find_dissector("sdp");
947 if (!mgcp_prefs_initialized)
949 mgcp_handle = create_dissector_handle(dissect_mgcp, proto_mgcp);
950 mgcp_tpkt_handle = create_dissector_handle(dissect_tpkt_mgcp, proto_mgcp);
951 mgcp_prefs_initialized = TRUE;
955 dissector_delete("tcp.port", gateway_tcp_port, mgcp_tpkt_handle);
956 dissector_delete("udp.port", gateway_udp_port, mgcp_handle);
957 dissector_delete("tcp.port", callagent_tcp_port, mgcp_tpkt_handle);
958 dissector_delete("udp.port", callagent_udp_port, mgcp_handle);
961 /* Set our port number for future use */
962 gateway_tcp_port = global_mgcp_gateway_tcp_port;
963 gateway_udp_port = global_mgcp_gateway_udp_port;
965 callagent_tcp_port = global_mgcp_callagent_tcp_port;
966 callagent_udp_port = global_mgcp_callagent_udp_port;
968 dissector_add("tcp.port", global_mgcp_gateway_tcp_port, mgcp_tpkt_handle);
969 dissector_add("udp.port", global_mgcp_gateway_udp_port, mgcp_handle);
970 dissector_add("tcp.port", global_mgcp_callagent_tcp_port, mgcp_tpkt_handle);
971 dissector_add("udp.port", global_mgcp_callagent_udp_port, mgcp_handle);
975 * is_mgcp_verb - A function for determining whether there is a
976 * MGCP verb at offset in tvb
979 * tvb - The tvbuff in which we are looking for an MGCP verb
980 * offset - The offset in tvb at which we are looking for a MGCP verb
981 * maxlength - The maximum distance from offset we may look for the
982 * characters that make up a MGCP verb.
983 * verb_name - The name for the verb code found (output)
985 * Return: TRUE if there is an MGCP verb at offset in tvb, otherwise FALSE
987 static gboolean is_mgcp_verb(tvbuff_t *tvb, gint offset, gint maxlength, const gchar **verb_name)
989 int returnvalue = FALSE;
992 /* Read the string into 'word' and see if it looks like the start of a verb */
993 if ((maxlength >= 4) && tvb_get_nstringz0(tvb, offset, sizeof(word), word))
995 if (((strncasecmp(word, "EPCF", 4) == 0) && (*verb_name = "EndpointConfiguration")) ||
996 ((strncasecmp(word, "CRCX", 4) == 0) && (*verb_name = "CreateConnection")) ||
997 ((strncasecmp(word, "MDCX", 4) == 0) && (*verb_name = "ModifyConnection")) ||
998 ((strncasecmp(word, "DLCX", 4) == 0) && (*verb_name = "DeleteConnection")) ||
999 ((strncasecmp(word, "RQNT", 4) == 0) && (*verb_name = "NotificationRequest")) ||
1000 ((strncasecmp(word, "NTFY", 4) == 0) && (*verb_name = "Notify")) ||
1001 ((strncasecmp(word, "AUEP", 4) == 0) && (*verb_name = "AuditEndpoint")) ||
1002 ((strncasecmp(word, "AUCX", 4) == 0) && (*verb_name = "AuditConnection")) ||
1003 ((strncasecmp(word, "RSIP", 4) == 0) && (*verb_name = "RestartInProgress")) ||
1004 ((strncasecmp(word, "MESG", 4) == 0) && (*verb_name = "Message")) ||
1005 (word[0] == 'X' && is_rfc2234_alpha(word[1]) && is_rfc2234_alpha(word[2]) &&
1006 is_rfc2234_alpha(word[3]) && (*verb_name = "*Experimental*")))
1012 /* May be whitespace after verb code - anything else is an error.. */
1013 if (returnvalue && maxlength >= 5)
1015 char next = tvb_get_guint8(tvb,4);
1016 if ((next != ' ') && (next != '\t'))
1018 returnvalue = FALSE;
1026 * is_mgcp_rspcode - A function for determining whether something which
1027 * looks roughly like a MGCP response code (3-digit number)
1028 * is at 'offset' in tvb
1031 * tvb - The tvbuff in which we are looking for an MGCP response code
1032 * offset - The offset in tvb at which we are looking for a MGCP response code
1033 * maxlength - The maximum distance from offset we may look for the
1034 * characters that make up a MGCP response code.
1036 * Return: TRUE if there is an MGCP response code at offset in tvb,
1039 static gboolean is_mgcp_rspcode(tvbuff_t *tvb, gint offset, gint maxlength)
1041 int returnvalue = FALSE;
1044 /* Do 1st 3 characters look like digits? */
1047 tvb_get_nstringz0(tvb, offset, sizeof(word), word);
1048 if (isdigit(word[0]) && isdigit(word[1]) && isdigit(word[2]))
1054 /* Maybe some white space after the 3rd digit - anything else is an error */
1055 if (returnvalue && maxlength >= 4)
1057 char next = tvb_get_guint8(tvb, 3);
1058 if ((next != ' ') && (next != '\t'))
1060 returnvalue = FALSE;
1068 * is_rfc2234_alpha - Indicates whether the character c is an alphabetical
1069 * character. This function is used instead of
1070 * isalpha because isalpha may deviate from the rfc2234
1071 * definition of ALPHA in some locales.
1074 * c - The character being checked for being an alphabetical character.
1076 * Return: TRUE if c is an upper or lower case alphabetical character,
1079 static gboolean is_rfc2234_alpha(guint8 c)
1081 return ((c <= 'Z' && c >= 'A' ) || (c <= 'z' && c >= 'a'));
1086 * tvb_parse_param - Parse the MGCP param into a type and a value.
1089 * tvb - The tvbuff containing the MGCP param we are to parse.
1090 * offset - The offset in tvb at which we will begin looking for a
1091 * MGCP parameter to parse.
1092 * len - The maximum distance from offset in tvb that we can look for
1093 * an MGCP parameter to parse.
1094 * hf - The place to write a pointer to the integer representing the
1095 * header field associated with the MGCP parameter parsed.
1097 * Returns: The offset in tvb where the value of the MGCP parameter
1100 static gint tvb_parse_param(tvbuff_t* tvb, gint offset, gint len, int** hf)
1102 gint returnvalue = -1, tvb_current_offset,counter;
1103 guint8 tempchar, plus_minus;
1106 tvb_current_offset = offset;
1112 tempchar = tvb_get_guint8(tvb,tvb_current_offset);
1117 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1119 *hf = &hf_mgcp_param_invalid;
1122 *hf = &hf_mgcp_param_rspack;
1125 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1127 *hf = &hf_mgcp_param_invalid;
1130 *hf = &hf_mgcp_param_bearerinfo;
1133 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1135 *hf = &hf_mgcp_param_invalid;
1138 *hf = &hf_mgcp_param_callid;
1141 tvb_current_offset++;
1142 if (len > (tvb_current_offset - offset) &&
1143 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1145 *hf = &hf_mgcp_param_connectionid;
1146 tvb_current_offset--;
1149 if (tempchar == '2')
1151 *hf = &hf_mgcp_param_secondconnectionid;
1155 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1157 *hf = &hf_mgcp_param_invalid;
1160 *hf = &hf_mgcp_param_notifiedentity;
1164 tvb_current_offset++;
1166 /* X: is RequestIdentifier */
1167 if (len > (tvb_current_offset - offset) &&
1168 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1170 *hf = &hf_mgcp_param_requestid;
1171 tvb_current_offset--;
1174 /* X+...: or X-....: are vendor extension parameters */
1176 if (len > (tvb_current_offset - offset) &&
1177 ((plus_minus = tvb_get_guint8(tvb,tvb_current_offset)) == '-' ||
1178 (plus_minus == '+')))
1180 /* Move past + or - */
1181 tvb_current_offset++;
1183 /* Keep going, through possible vendor param name */
1185 ((len > (counter + tvb_current_offset-offset)) &&
1186 (is_rfc2234_alpha(tempchar = tvb_get_guint8(tvb, tvb_current_offset+counter)) ||
1187 isdigit(tempchar))) ;
1190 if (tempchar == ':')
1192 /* Looks like a valid vendor param name */
1193 tvb_current_offset += counter;
1197 *hf = &hf_mgcp_param_extension_critical;
1200 *hf = &hf_mgcp_param_extension;
1207 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1209 *hf = &hf_mgcp_param_invalid;
1212 *hf = &hf_mgcp_param_localconnoptions;
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_connectionmode;
1220 tvb_current_offset--;
1223 if (tempchar == 'D')
1225 *hf = &hf_mgcp_param_maxmgcpdatagram;
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_reqevents;
1234 tvb_current_offset--;
1237 if ( tempchar == 'M')
1239 *hf = &hf_mgcp_param_restartmethod;
1242 if (tempchar == 'D')
1244 *hf = &hf_mgcp_param_restartdelay;
1248 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1250 *hf = &hf_mgcp_param_invalid;
1253 *hf = &hf_mgcp_param_signalreq;
1254 buf = &(mi->signalReq);
1257 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1259 *hf = &hf_mgcp_param_invalid;
1262 *hf = &hf_mgcp_param_digitmap;
1263 mi->hasDigitMap = TRUE;
1266 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1268 *hf = &hf_mgcp_param_invalid;
1271 *hf = &hf_mgcp_param_observedevent;
1272 buf = &(mi->observedEvents);
1275 tvb_current_offset++;
1276 if (len > (tvb_current_offset - offset) &&
1277 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1279 *hf = &hf_mgcp_param_connectionparam;
1280 tvb_current_offset--;
1283 if ( tempchar == 'L')
1285 *hf = &hf_mgcp_param_packagelist;
1289 tvb_current_offset++;
1290 if (len > (tvb_current_offset - offset) &&
1291 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1293 *hf = &hf_mgcp_param_reasoncode;
1294 tvb_current_offset--;
1297 if ( tempchar == 'S')
1299 *hf = &hf_mgcp_param_eventstates;
1303 tvb_current_offset++;
1304 if (len > (tvb_current_offset - offset) &&
1305 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1307 *hf = &hf_mgcp_param_specificendpoint;
1308 tvb_current_offset--;
1311 if (tempchar == '2')
1313 *hf = &hf_mgcp_param_secondendpointid;
1317 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1319 *hf = &hf_mgcp_param_invalid;
1322 *hf = &hf_mgcp_param_reqinfo;
1325 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1327 *hf = &hf_mgcp_param_invalid;
1330 *hf = &hf_mgcp_param_quarantinehandling;
1333 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1335 *hf = &hf_mgcp_param_invalid;
1338 *hf = &hf_mgcp_param_detectedevents;
1341 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1343 *hf = &hf_mgcp_param_invalid;
1346 *hf = &hf_mgcp_param_capabilities;
1350 *hf = &hf_mgcp_param_invalid;
1354 /* Move to (hopefully) the colon */
1355 tvb_current_offset++;
1357 /* Add a recognised parameter type if we have one */
1358 if (*hf != NULL && len > (tvb_current_offset - offset) &&
1359 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1361 tvb_current_offset++;
1362 tvb_current_offset = tvb_skip_wsp(tvb,tvb_current_offset, (len - tvb_current_offset + offset));
1363 returnvalue = tvb_current_offset;
1365 /* set the observedEvents or signalReq used in Voip Calls analysis */
1367 *buf = tvb_get_ephemeral_string(tvb, tvb_current_offset, (len - tvb_current_offset + offset));
1373 /* Was an empty line */
1374 *hf = &hf_mgcp_param_invalid;
1377 /* For these types, show the whole line */
1378 if ((*hf == &hf_mgcp_param_invalid) ||
1379 (*hf == &hf_mgcp_param_extension) || (*hf == &hf_mgcp_param_extension_critical))
1381 returnvalue = offset;
1389 * dissect_mgcp_firstline - Dissects the firstline of an MGCP message.
1390 * Adds the appropriate headers fields to
1391 * tree for the dissection of the first line
1392 * of an MGCP message.
1395 * tvb - The tvb containing the first line of an MGCP message. This
1396 * tvb is presumed to ONLY contain the first line of the MGCP
1398 * pinfo - The packet info for the packet. This is not really used
1399 * by this function but is passed through so as to retain the
1400 * style of a dissector.
1401 * tree - The tree from which to hang the structured information parsed
1402 * from the first line of the MGCP message.
1404 static void dissect_mgcp_firstline(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1406 gint tvb_current_offset,tvb_previous_offset,tvb_len,tvb_current_len;
1407 gint tokennum, tokenlen;
1408 char *transid = NULL;
1410 char *endpointId = NULL;
1411 mgcp_type_t mgcp_type = MGCP_OTHERS;
1412 conversation_t* conversation;
1413 mgcp_call_info_key mgcp_call_key;
1414 mgcp_call_info_key *new_mgcp_call_key = NULL;
1415 mgcp_call_t *mgcp_call = NULL;
1418 const gchar *verb_description = "";
1419 char code_with_verb[64] = ""; /* To fit "<4-letter-code> (<longest-verb>)" */
1421 static address null_address = { AT_NONE, 0, NULL };
1422 tvb_previous_offset = 0;
1423 tvb_len = tvb_length(tvb);
1424 tvb_current_len = tvb_len;
1425 tvb_current_offset = tvb_previous_offset;
1426 mi->is_duplicate = FALSE;
1427 mi->request_available = FALSE;
1435 tvb_current_len = tvb_length_remaining(tvb,tvb_previous_offset);
1436 tvb_current_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_current_len, ' ');
1437 if (tvb_current_offset == -1)
1439 tvb_current_offset = tvb_len;
1440 tokenlen = tvb_current_len;
1444 tokenlen = tvb_current_offset - tvb_previous_offset;
1449 THROW(ReportedBoundsError);
1450 code = tvb_format_text(tvb,tvb_previous_offset,tokenlen);
1451 strncpy(mi->code,code,4);
1453 if (is_mgcp_verb(tvb,tvb_previous_offset,tvb_current_len,&verb_description))
1455 mgcp_type = MGCP_REQUEST;
1456 if (verb_description != NULL)
1458 /* Can show verb along with code if known */
1459 sprintf(code_with_verb, "%s (%s)", code, verb_description);
1462 proto_tree_add_string_format(tree, hf_mgcp_req_verb, tvb,
1463 tvb_previous_offset, tokenlen,
1465 strlen(code_with_verb) ? code_with_verb : code);
1468 if (is_mgcp_rspcode(tvb,tvb_previous_offset,tvb_current_len))
1470 mgcp_type = MGCP_RESPONSE;
1471 rspcode = atoi(code);
1472 mi->rspcode = rspcode;
1473 proto_tree_add_uint(tree,hf_mgcp_rsp_rspcode, tvb,
1474 tvb_previous_offset, tokenlen, rspcode);
1483 transid = tvb_format_text(tvb,tvb_previous_offset,tokenlen);
1484 /* XXX - what if this isn't a valid text string? */
1485 mi->transid = atol(transid);
1486 proto_tree_add_string(tree, hf_mgcp_transid, tvb,
1487 tvb_previous_offset, tokenlen, transid);
1491 if (mgcp_type == MGCP_REQUEST)
1493 endpointId = tvb_format_text(tvb, tvb_previous_offset,tokenlen);
1494 mi->endpointId = ep_strdup(endpointId);
1495 proto_tree_add_string(tree,hf_mgcp_req_endpoint, tvb,
1496 tvb_previous_offset, tokenlen, endpointId);
1499 if (mgcp_type == MGCP_RESPONSE)
1501 if (tvb_current_offset < tvb_len)
1503 tokenlen = tvb_find_line_end(tvb, tvb_previous_offset,
1504 -1, &tvb_current_offset, FALSE);
1508 tokenlen = tvb_current_len;
1510 proto_tree_add_string(tree, hf_mgcp_rsp_rspstring, tvb,
1511 tvb_previous_offset, tokenlen,
1512 tvb_format_text(tvb, tvb_previous_offset,
1518 if ((tokennum == 3 && mgcp_type == MGCP_REQUEST))
1520 if (tvb_current_offset < tvb_len )
1522 tokenlen = tvb_find_line_end(tvb, tvb_previous_offset,
1523 -1, &tvb_current_offset,FALSE);
1527 tokenlen = tvb_current_len;
1529 proto_tree_add_string(tree,hf_mgcp_version, tvb,
1530 tvb_previous_offset, tokenlen,
1531 tvb_format_text(tvb,tvb_previous_offset,
1535 if (tvb_current_offset < tvb_len)
1537 tvb_previous_offset = tvb_skip_wsp(tvb, tvb_current_offset,
1541 } while (tvb_current_offset < tvb_len && tvb_previous_offset < tvb_len && tokennum <= 3);
1546 proto_tree_add_boolean_hidden(tree, hf_mgcp_rsp, tvb, 0, 0, TRUE);
1547 /* Check for MGCP response. A response must match a call that
1548 we've seen, and the response must be sent to the same
1549 port and address that the call came from, and must
1550 come from the port to which the call was sent.
1552 If the transport is connection-oriented (we check, for
1553 now, only for "pinfo->ptype" of PT_TCP), we take
1554 into account the address from which the call was sent
1555 and the address to which the call was sent, because
1556 the addresses of the two endpoints should be the same
1557 for all calls and replies.
1559 If the transport is connectionless, we don't worry
1560 about the address to which the call was sent and from
1561 which the reply was sent, because there's no
1562 guarantee that the reply will come from the address
1563 to which the call was sent. */
1564 if (pinfo->ptype == PT_TCP)
1566 conversation = find_conversation(pinfo->fd->num, &pinfo->src,
1567 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1568 pinfo->destport, 0);
1572 /* XXX - can we just use NO_ADDR_B? Unfortunately,
1573 * you currently still have to pass a non-null
1574 * pointer for the second address argument even
1577 conversation = find_conversation(pinfo->fd->num, &null_address,
1578 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1579 pinfo->destport, 0);
1581 if (conversation != NULL)
1583 /* Look only for matching request, if
1584 matching conversation is available. */
1585 mgcp_call_key.transid = mi->transid;
1586 mgcp_call_key.conversation = conversation;
1587 mgcp_call = g_hash_table_lookup(mgcp_calls, &mgcp_call_key);
1590 /* Indicate the frame to which this is a reply. */
1591 if (mgcp_call->req_num)
1594 mi->request_available = TRUE;
1595 mgcp_call->responded = TRUE;
1596 mi->req_num = mgcp_call->req_num;
1597 strcpy(mi->code,mgcp_call->code);
1598 item = proto_tree_add_uint_format(tree, hf_mgcp_req_frame,
1599 tvb, 0, 0, mgcp_call->req_num,
1600 "This is a response to a request in frame %u",
1601 mgcp_call->req_num);
1602 PROTO_ITEM_SET_GENERATED(item);
1603 nstime_delta(&delta, &pinfo->fd->abs_ts, &mgcp_call->req_time);
1604 item = proto_tree_add_time(tree, hf_mgcp_time, tvb, 0, 0, &delta);
1605 PROTO_ITEM_SET_GENERATED(item);
1608 if (mgcp_call->rsp_num == 0)
1610 /* We have not yet seen a response to that call, so
1611 this must be the first response; remember its
1613 mgcp_call->rsp_num = pinfo->fd->num;
1617 /* We have seen a response to this call - but was it
1618 *this* response? (disregard provisional responses) */
1619 if ((mgcp_call->rsp_num != pinfo->fd->num) &&
1620 (mi->rspcode >= 200) &&
1621 (mi->rspcode == mgcp_call->rspcode))
1623 /* No, so it's a duplicate response. Mark it as such. */
1624 mi->is_duplicate = TRUE;
1625 if (check_col(pinfo->cinfo, COL_INFO))
1627 col_append_fstr(pinfo->cinfo, COL_INFO,
1628 ", Duplicate Response %u",
1634 proto_tree_add_uint_hidden(tree, hf_mgcp_dup, tvb, 0,0, mi->transid);
1635 item = proto_tree_add_uint(tree, hf_mgcp_rsp_dup,
1636 tvb, 0, 0, mi->transid);
1637 PROTO_ITEM_SET_GENERATED(item);
1638 item = proto_tree_add_uint(tree, hf_mgcp_rsp_dup_frame,
1639 tvb, 0, 0, mgcp_call->rsp_num);
1640 PROTO_ITEM_SET_GENERATED(item);
1644 /* Now store the response code (after comparison above) */
1645 mgcp_call->rspcode = mi->rspcode;
1650 proto_tree_add_boolean_hidden(tree, hf_mgcp_req, tvb, 0, 0, TRUE);
1651 /* Keep track of the address and port whence the call came,
1652 * and the port to which the call is being sent, so that
1653 * we can match up calls with replies.
1655 * If the transport is connection-oriented (we check, for
1656 * now, only for "pinfo->ptype" of PT_TCP), we take
1657 * into account the address from which the call was sent
1658 * and the address to which the call was sent, because
1659 * the addresses of the two endpoints should be the same
1660 * for all calls and replies.
1662 * If the transport is connectionless, we don't worry
1663 * about the address to which the call was sent and from
1664 * which the reply was sent, because there's no
1665 * guarantee that the reply will come from the address
1666 * to which the call was sent.
1668 if (pinfo->ptype == PT_TCP)
1670 conversation = find_conversation(pinfo->fd->num, &pinfo->src,
1671 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1672 pinfo->destport, 0);
1677 * XXX - can we just use NO_ADDR_B? Unfortunately,
1678 * you currently still have to pass a non-null
1679 * pointer for the second address argument even
1682 conversation = find_conversation(pinfo->fd->num, &pinfo->src,
1683 &null_address, pinfo->ptype, pinfo->srcport,
1684 pinfo->destport, 0);
1686 if (conversation == NULL)
1688 /* It's not part of any conversation - create a new one. */
1689 if (pinfo->ptype == PT_TCP)
1691 conversation = conversation_new(pinfo->fd->num, &pinfo->src,
1692 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1693 pinfo->destport, 0);
1697 conversation = conversation_new(pinfo->fd->num, &pinfo->src,
1698 &null_address, pinfo->ptype, pinfo->srcport,
1699 pinfo->destport, 0);
1703 /* Prepare the key data */
1704 mgcp_call_key.transid = mi->transid;
1705 mgcp_call_key.conversation = conversation;
1707 /* Look up the request */
1708 mgcp_call = g_hash_table_lookup(mgcp_calls, &mgcp_call_key);
1709 if (mgcp_call != NULL)
1711 /* We've seen a request with this TRANSID, with the same
1712 source and destination, before - but was it
1714 if (pinfo->fd->num != mgcp_call->req_num)
1716 /* No, so it's a duplicate request. Mark it as such. */
1717 mi->is_duplicate = TRUE;
1718 mi->req_num = mgcp_call->req_num;
1719 if (check_col(pinfo->cinfo, COL_INFO))
1721 col_append_fstr(pinfo->cinfo, COL_INFO,
1722 ", Duplicate Request %u",
1728 proto_tree_add_uint_hidden(tree, hf_mgcp_dup, tvb, 0,0, mi->transid);
1729 item = proto_tree_add_uint(tree, hf_mgcp_req_dup, tvb, 0,0, mi->transid);
1730 PROTO_ITEM_SET_GENERATED(item);
1731 item = proto_tree_add_uint(tree, hf_mgcp_req_dup_frame, tvb, 0,0, mi->req_num);
1732 PROTO_ITEM_SET_GENERATED(item);
1738 /* Prepare the value data.
1739 "req_num" and "rsp_num" are frame numbers;
1740 frame numbers are 1-origin, so we use 0
1741 to mean "we don't yet know in which frame
1742 the reply for this call appears". */
1743 new_mgcp_call_key = g_mem_chunk_alloc(mgcp_call_info_key_chunk);
1744 *new_mgcp_call_key = mgcp_call_key;
1745 mgcp_call = g_mem_chunk_alloc(mgcp_call_info_value_chunk);
1746 mgcp_call->req_num = pinfo->fd->num;
1747 mgcp_call->rsp_num = 0;
1748 mgcp_call->transid = mi->transid;
1749 mgcp_call->responded = FALSE;
1750 mgcp_call->req_time=pinfo->fd->abs_ts;
1751 strcpy(mgcp_call->code,mi->code);
1754 g_hash_table_insert(mgcp_calls, new_mgcp_call_key, mgcp_call);
1756 if (mgcp_call && mgcp_call->rsp_num)
1758 proto_item* item = proto_tree_add_uint_format(tree, hf_mgcp_rsp_frame,
1759 tvb, 0, 0, mgcp_call->rsp_num,
1760 "The response to this request is in frame %u",
1761 mgcp_call->rsp_num);
1762 PROTO_ITEM_SET_GENERATED(item);
1769 mi->mgcp_type = mgcp_type;
1772 mi->req_time.secs=mgcp_call->req_time.secs;
1773 mi->req_time.nsecs=mgcp_call->req_time.nsecs;
1777 tap_queue_packet(mgcp_tap, pinfo, mi);
1781 * dissect_mgcp_params - Dissects the parameters of an MGCP message.
1782 * Adds the appropriate headers fields to
1783 * tree for the dissection of the parameters
1784 * of an MGCP message.
1787 * tvb - The tvb containing the parameters of an MGCP message. This
1788 * tvb is presumed to ONLY contain the part of the MGCP
1789 * message which contains the MGCP parameters.
1790 * tree - The tree from which to hang the structured information parsed
1791 * from the parameters of the MGCP message.
1793 static void dissect_mgcp_params(tvbuff_t *tvb, proto_tree *tree)
1795 int linelen, tokenlen, *my_param;
1796 gint tvb_lineend,tvb_current_len, tvb_linebegin,tvb_len,old_lineend;
1797 gint tvb_tokenbegin;
1798 proto_tree *mgcp_param_ti, *mgcp_param_tree;
1800 tvb_len = tvb_length(tvb);
1802 tvb_current_len = tvb_length_remaining(tvb,tvb_linebegin);
1803 tvb_lineend = tvb_linebegin;
1807 mgcp_param_ti = proto_tree_add_item(tree, hf_mgcp_params, tvb,
1808 tvb_linebegin, tvb_len, FALSE);
1809 proto_item_set_text(mgcp_param_ti, "Parameters");
1810 mgcp_param_tree = proto_item_add_subtree(mgcp_param_ti, ett_mgcp_param);
1812 /* Parse the parameters */
1813 while (tvb_lineend < tvb_len)
1815 old_lineend = tvb_lineend;
1816 linelen = tvb_find_line_end(tvb, tvb_linebegin, -1,&tvb_lineend,FALSE);
1817 tvb_tokenbegin = tvb_parse_param(tvb, tvb_linebegin, linelen, &my_param);
1821 if (*my_param == hf_mgcp_param_connectionparam)
1823 tokenlen = tvb_find_line_end(tvb,tvb_tokenbegin,-1,&tvb_lineend,FALSE);
1824 dissect_mgcp_connectionparams(mgcp_param_tree, tvb, tvb_linebegin,
1825 tvb_tokenbegin - tvb_linebegin, tokenlen);
1828 if (*my_param == hf_mgcp_param_localconnoptions)
1830 tokenlen = tvb_find_line_end(tvb,tvb_tokenbegin,-1,&tvb_lineend,FALSE);
1831 dissect_mgcp_localconnectionoptions(mgcp_param_tree, tvb, tvb_linebegin,
1832 tvb_tokenbegin - tvb_linebegin, tokenlen);
1836 tokenlen = tvb_find_line_end(tvb,tvb_tokenbegin,-1,&tvb_lineend,FALSE);
1837 proto_tree_add_string(mgcp_param_tree,*my_param, tvb,
1838 tvb_linebegin, linelen,
1839 tvb_format_text(tvb,tvb_tokenbegin, tokenlen));
1843 tvb_linebegin = tvb_lineend;
1844 /* Its a infinite loop if we didn't advance (or went backwards) */
1845 if (old_lineend >= tvb_lineend)
1847 THROW(ReportedBoundsError);
1853 /* Dissect the connection params */
1855 dissect_mgcp_connectionparams(proto_tree *parent_tree, tvbuff_t *tvb, gint offset, gint param_type_len, gint param_val_len)
1857 proto_tree *tree = parent_tree;
1858 proto_item *item = NULL;
1860 gchar *tokenline = NULL;
1861 gchar **tokens = NULL;
1862 gchar **typval = NULL;
1870 item = proto_tree_add_item(parent_tree, hf_mgcp_param_connectionparam, tvb, offset, param_type_len+param_val_len, FALSE);
1871 tree = proto_item_add_subtree(item, ett_mgcp_param_connectionparam);
1875 offset += param_type_len; /* skip the P: */
1876 tokenline = tvb_get_ephemeral_string(tvb, offset, param_val_len);
1878 /* Split into type=value pairs separated by comma */
1879 tokens = ep_strsplit(tokenline, ",", -1);
1881 for (i = 0; tokens[i] != NULL; i++)
1883 tokenlen = strlen(tokens[i]);
1884 typval = ep_strsplit(tokens[i], "=", 2);
1885 if ((typval[0] != NULL) && (typval[1] != NULL))
1887 if (!strcasecmp(g_strstrip(typval[0]), "PS"))
1889 hf_uint = hf_mgcp_param_connectionparam_ps;
1891 else if (!strcasecmp(g_strstrip(typval[0]), "OS"))
1893 hf_uint = hf_mgcp_param_connectionparam_os;
1895 else if (!strcasecmp(g_strstrip(typval[0]), "PR"))
1897 hf_uint = hf_mgcp_param_connectionparam_pr;
1899 else if (!strcasecmp(g_strstrip(typval[0]), "OR"))
1901 hf_uint = hf_mgcp_param_connectionparam_or;
1903 else if (!strcasecmp(g_strstrip(typval[0]), "PL"))
1905 hf_uint = hf_mgcp_param_connectionparam_pl;
1907 else if (!strcasecmp(g_strstrip(typval[0]), "JI"))
1909 hf_uint = hf_mgcp_param_connectionparam_ji;
1911 else if (!strcasecmp(g_strstrip(typval[0]), "LA"))
1913 hf_uint = hf_mgcp_param_connectionparam_la;
1915 else if (!strcasecmp(g_strstrip(typval[0]), "PC/RPS"))
1917 hf_uint = hf_mgcp_param_connectionparam_pcrps;
1918 } else if (!strcasecmp(g_strstrip(typval[0]), "PC/ROS"))
1920 hf_uint = hf_mgcp_param_connectionparam_pcros;
1922 else if (!strcasecmp(g_strstrip(typval[0]), "PC/RPL"))
1924 hf_uint = hf_mgcp_param_connectionparam_pcrpl;
1926 else if (!strcasecmp(g_strstrip(typval[0]), "PC/RJI"))
1928 hf_uint = hf_mgcp_param_connectionparam_pcrji;
1930 else if (!strncasecmp(g_strstrip(typval[0]), "X-", 2))
1932 hf_string = hf_mgcp_param_connectionparam_x;
1944 proto_tree_add_uint(tree, hf_uint, tvb, offset, tokenlen, atol(typval[1]));
1946 else if (hf_string != -1)
1948 proto_tree_add_string(tree, hf_string, tvb, offset, tokenlen, g_strstrip(typval[1]));
1952 proto_tree_add_text(tree, tvb, offset, tokenlen, "Unknown parameter: %s", tokens[i]);
1958 proto_tree_add_text(tree, tvb, offset, tokenlen, "Malformed parameter: %s", tokens[i]);
1960 offset += tokenlen + 1; /* 1 extra for the delimiter */
1965 /* Dissect the local connection option */
1967 dissect_mgcp_localconnectionoptions(proto_tree *parent_tree, tvbuff_t *tvb, gint offset, gint param_type_len, gint param_val_len)
1969 proto_tree *tree = parent_tree;
1970 proto_item *item = NULL;
1972 gchar *tokenline = NULL;
1973 gchar **tokens = NULL;
1974 gchar **typval = NULL;
1982 item = proto_tree_add_item(parent_tree, hf_mgcp_param_localconnoptions, tvb, offset, param_type_len+param_val_len, FALSE);
1983 tree = proto_item_add_subtree(item, ett_mgcp_param_localconnectionoptions);
1987 offset += param_type_len; /* skip the L: */
1988 tokenline = tvb_get_ephemeral_string(tvb, offset, param_val_len);
1990 /* Split into type=value pairs separated by comma */
1991 tokens = ep_strsplit(tokenline, ",", -1);
1992 for (i = 0; tokens[i] != NULL; i++)
1997 tokenlen = strlen(tokens[i]);
1998 typval = ep_strsplit(tokens[i], ":", 2);
1999 if ((typval[0] != NULL) && (typval[1] != NULL))
2001 if (!strcasecmp(g_strstrip(typval[0]), "p"))
2003 hf_uint = hf_mgcp_param_localconnoptions_p;
2005 else if (!strcasecmp(g_strstrip(typval[0]), "a"))
2007 hf_string = hf_mgcp_param_localconnoptions_a;
2009 else if (!strcasecmp(g_strstrip(typval[0]), "s"))
2011 hf_string = hf_mgcp_param_localconnoptions_s;
2013 else if (!strcasecmp(g_strstrip(typval[0]), "e"))
2015 hf_string = hf_mgcp_param_localconnoptions_e;
2017 else if (!strcasecmp(g_strstrip(typval[0]), "sc-rtp"))
2019 hf_string = hf_mgcp_param_localconnoptions_scrtp;
2021 else if (!strcasecmp(g_strstrip(typval[0]), "sc-rtcp"))
2023 hf_string = hf_mgcp_param_localconnoptions_scrtcp;
2025 else if (!strcasecmp(g_strstrip(typval[0]), "b"))
2027 hf_string = hf_mgcp_param_localconnoptions_b;
2029 else if (!strcasecmp(g_strstrip(typval[0]), "es-ccd"))
2031 hf_string = hf_mgcp_param_localconnoptions_esccd;
2033 else if (!strcasecmp(g_strstrip(typval[0]), "es-cci"))
2035 hf_string = hf_mgcp_param_localconnoptions_escci;
2037 else if (!strcasecmp(g_strstrip(typval[0]), "dq-gi"))
2039 hf_string = hf_mgcp_param_localconnoptions_dqgi;
2041 else if (!strcasecmp(g_strstrip(typval[0]), "dq-rd"))
2043 hf_string = hf_mgcp_param_localconnoptions_dqrd;
2045 else if (!strcasecmp(g_strstrip(typval[0]), "dq-ri"))
2047 hf_string = hf_mgcp_param_localconnoptions_dqri;
2049 else if (!strcasecmp(g_strstrip(typval[0]), "dq-rr"))
2051 hf_string = hf_mgcp_param_localconnoptions_dqrr;
2053 else if (!strcasecmp(g_strstrip(typval[0]), "k"))
2055 hf_string = hf_mgcp_param_localconnoptions_k;
2057 else if (!strcasecmp(g_strstrip(typval[0]), "gc"))
2059 hf_uint = hf_mgcp_param_localconnoptions_gc;
2061 else if (!strcasecmp(g_strstrip(typval[0]), "fmtp"))
2063 hf_string = hf_mgcp_param_localconnoptions_fmtp;
2065 else if (!strcasecmp(g_strstrip(typval[0]), "nt"))
2067 hf_string = hf_mgcp_param_localconnoptions_nt;
2069 else if (!strcasecmp(g_strstrip(typval[0]), "o-fmtp"))
2071 hf_string = hf_mgcp_param_localconnoptions_ofmtp;
2073 else if (!strcasecmp(g_strstrip(typval[0]), "r"))
2075 hf_string = hf_mgcp_param_localconnoptions_r;
2077 else if (!strcasecmp(g_strstrip(typval[0]), "t"))
2079 hf_string = hf_mgcp_param_localconnoptions_t;
2081 else if (!strcasecmp(g_strstrip(typval[0]), "r-cnf"))
2083 hf_string = hf_mgcp_param_localconnoptions_rcnf;
2085 else if (!strcasecmp(g_strstrip(typval[0]), "r-dir"))
2087 hf_string = hf_mgcp_param_localconnoptions_rdir;
2089 else if (!strcasecmp(g_strstrip(typval[0]), "r-sh"))
2091 hf_string = hf_mgcp_param_localconnoptions_rsh;
2104 proto_tree_add_uint(tree, hf_uint, tvb, offset, tokenlen, atol(typval[1]));
2106 else if (hf_string != -1)
2108 proto_tree_add_string(tree, hf_string, tvb, offset, tokenlen, g_strstrip(typval[1]));
2112 proto_tree_add_text(tree, tvb, offset, tokenlen, "Unknown parameter: %s", tokens[i]);
2118 proto_tree_add_text(tree, tvb, offset, tokenlen, "Malformed parameter: %s", tokens[i]);
2120 offset += tokenlen + 1; /* 1 extra for the delimiter */
2127 * tvb_skip_wsp - Returns the position in tvb of the first non-whitespace
2128 * character following offset or offset + maxlength -1 whichever
2132 * tvb - The tvbuff in which we are skipping whitespace.
2133 * offset - The offset in tvb from which we begin trying to skip whitespace.
2134 * maxlength - The maximum distance from offset that we may try to skip
2137 * Returns: The position in tvb of the first non-whitespace
2138 * character following offset or offset + maxlength -1 whichever
2141 static gint tvb_skip_wsp(tvbuff_t* tvb, gint offset, gint maxlength)
2143 gint counter = offset;
2144 gint end = offset + maxlength,tvb_len;
2147 /* Get the length remaining */
2148 tvb_len = tvb_length(tvb);
2149 end = offset + maxlength;
2155 /* Skip past spaces and tabs until run out or meet something else */
2156 for (counter = offset;
2158 ((tempchar = tvb_get_guint8(tvb,counter)) == ' ' ||
2166 * tvb_find_null_line - Returns the length from offset to the first null
2167 * line found (a null line is a line that begins
2168 * with a CR or LF. The offset to the first character
2169 * after the null line is written into the gint pointed
2170 * to by next_offset.
2173 * tvb - The tvbuff in which we are looking for a null line.
2174 * offset - The offset in tvb at which we will begin looking for
2176 * len - The maximum distance from offset in tvb that we will look for
2177 * a null line. If it is -1 we will look to the end of the buffer.
2179 * next_offset - The location to write the offset of first character
2180 * FOLLOWING the null line.
2182 * Returns: The length from offset to the first character BEFORE
2185 static gint tvb_find_null_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset)
2187 gint tvb_lineend,tvb_current_len,tvb_linebegin,maxoffset;
2190 tvb_linebegin = offset;
2191 tvb_lineend = tvb_linebegin;
2193 /* Simple setup to allow for the traditional -1 search to the end of the tvbuff */
2196 tvb_current_len = len;
2200 tvb_current_len = tvb_length_remaining(tvb,offset);
2203 maxoffset = (tvb_current_len - 1) + offset;
2205 /* Loop around until we either find a line begining with a carriage return
2206 or newline character or until we hit the end of the tvbuff. */
2209 tvb_linebegin = tvb_lineend;
2210 tvb_current_len = tvb_length_remaining(tvb,tvb_linebegin);
2211 tvb_find_line_end(tvb, tvb_linebegin, tvb_current_len, &tvb_lineend,FALSE);
2212 tempchar = tvb_get_guint8(tvb,tvb_linebegin);
2213 } while (tempchar != '\r' && tempchar != '\n' && tvb_lineend <= maxoffset);
2216 *next_offset = tvb_lineend;
2218 if (tvb_lineend <= maxoffset)
2220 tvb_current_len = tvb_linebegin - offset;
2224 tvb_current_len = tvb_length_remaining(tvb,offset);
2227 return tvb_current_len;
2231 * tvb_find_dot_line - Returns the length from offset to the first line
2232 * containing only a dot (.) character. A line
2233 * containing only a dot is used to indicate a
2234 * separation between multiple MGCP messages
2235 * piggybacked in the same UDP packet.
2238 * tvb - The tvbuff in which we are looking for a dot line.
2239 * offset - The offset in tvb at which we will begin looking for
2241 * len - The maximum distance from offset in tvb that we will look for
2242 * a dot line. If it is -1 we will look to the end of the buffer.
2244 * next_offset - The location to write the offset of first character
2245 * FOLLOWING the dot line.
2247 * Returns: The length from offset to the first character BEFORE
2248 * the dot line or -1 if the character at offset is a .
2249 * followed by a newline or a carriage return.
2251 static gint tvb_find_dot_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset)
2253 gint tvb_current_offset, tvb_current_len, maxoffset,tvb_len;
2255 tvb_current_offset = offset;
2256 tvb_current_len = len;
2257 tvb_len = tvb_length(tvb);
2261 maxoffset = tvb_len - 1;
2265 maxoffset = (len - 1) + offset;
2267 tvb_current_offset = offset -1;
2271 tvb_current_offset = tvb_find_guint8(tvb, tvb_current_offset+1,
2272 tvb_current_len, '.');
2273 tvb_current_len = maxoffset - tvb_current_offset + 1;
2275 /* If we didn't find a . then break out of the loop */
2276 if (tvb_current_offset == -1)
2281 /* Do we have and characters following the . ? */
2282 if (tvb_current_offset < maxoffset)
2284 tempchar = tvb_get_guint8(tvb,tvb_current_offset+1);
2285 /* Are the characters that follow the dot a newline or carriage return ? */
2286 if (tempchar == '\r' || tempchar == '\n')
2288 /* Do we have any charaters that proceed the . ? */
2289 if (tvb_current_offset == 0)
2295 tempchar = tvb_get_guint8(tvb,tvb_current_offset-1);
2297 /* Are the characters that follow the dot a newline or a
2298 carriage return ? */
2299 if (tempchar == '\r' || tempchar == '\n')
2307 if (tvb_current_offset == maxoffset)
2309 if (tvb_current_offset == 0)
2315 tempchar = tvb_get_guint8(tvb,tvb_current_offset-1);
2316 if (tempchar == '\r' || tempchar == '\n')
2322 } while (tvb_current_offset < maxoffset);
2326 * So now we either have the tvb_current_offset of a . in a dot line
2327 * or a tvb_current_offset of -1
2329 if (tvb_current_offset == -1)
2331 tvb_current_offset = maxoffset +1;
2332 *next_offset = maxoffset + 1;
2336 tvb_find_line_end(tvb,tvb_current_offset,tvb_current_len,next_offset,FALSE);
2339 if (tvb_current_offset == offset)
2341 tvb_current_len = -1;
2345 tvb_current_len = tvb_current_offset - offset;
2348 return tvb_current_len;