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.
44 #include <epan/packet.h>
45 #include <epan/emem.h>
46 #include <epan/prefs.h>
47 #include <epan/conversation.h>
49 #include <epan/strutil.h>
50 #include "packet-mgcp.h"
53 #define TCP_PORT_MGCP_GATEWAY 2427
54 #define UDP_PORT_MGCP_GATEWAY 2427
55 #define TCP_PORT_MGCP_CALLAGENT 2727
56 #define UDP_PORT_MGCP_CALLAGENT 2727
59 /* Define the mgcp proto */
60 static int proto_mgcp = -1;
62 /* Define many many headers for mgcp */
63 static int hf_mgcp_req = -1;
64 static int hf_mgcp_req_verb = -1;
65 static int hf_mgcp_req_endpoint = -1;
66 static int hf_mgcp_req_frame = -1;
67 static int hf_mgcp_rsp = -1;
68 static int hf_mgcp_rsp_frame = -1;
69 static int hf_mgcp_time = -1;
70 static int hf_mgcp_transid = -1;
71 static int hf_mgcp_version = -1;
72 static int hf_mgcp_rsp_rspcode = -1;
73 static int hf_mgcp_rsp_rspstring = -1;
74 static int hf_mgcp_params = -1;
75 static int hf_mgcp_param_rspack = -1;
76 static int hf_mgcp_param_bearerinfo = -1;
77 static int hf_mgcp_param_callid = -1;
78 static int hf_mgcp_param_connectionid = -1;
79 static int hf_mgcp_param_secondconnectionid = -1;
80 static int hf_mgcp_param_notifiedentity = -1;
81 static int hf_mgcp_param_requestid = -1;
82 static int hf_mgcp_param_localconnoptions = -1;
83 static int hf_mgcp_param_localconnoptions_p = -1;
84 static int hf_mgcp_param_localconnoptions_a = -1;
85 static int hf_mgcp_param_localconnoptions_s = -1;
86 static int hf_mgcp_param_localconnoptions_e = -1;
87 static int hf_mgcp_param_localconnoptions_scrtp = -1;
88 static int hf_mgcp_param_localconnoptions_scrtcp = -1;
89 static int hf_mgcp_param_localconnoptions_b = -1;
90 static int hf_mgcp_param_localconnoptions_esccd = -1;
91 static int hf_mgcp_param_localconnoptions_escci = -1;
92 static int hf_mgcp_param_localconnoptions_dqgi = -1;
93 static int hf_mgcp_param_localconnoptions_dqrd = -1;
94 static int hf_mgcp_param_localconnoptions_dqri = -1;
95 static int hf_mgcp_param_localconnoptions_dqrr = -1;
96 static int hf_mgcp_param_localconnoptions_k = -1;
97 static int hf_mgcp_param_localconnoptions_gc = -1;
98 static int hf_mgcp_param_localconnoptions_fmtp = -1;
99 static int hf_mgcp_param_localconnoptions_nt = -1;
100 static int hf_mgcp_param_localconnoptions_ofmtp = -1;
101 static int hf_mgcp_param_localconnoptions_r = -1;
102 static int hf_mgcp_param_localconnoptions_t = -1;
103 static int hf_mgcp_param_localconnoptions_rcnf = -1;
104 static int hf_mgcp_param_localconnoptions_rdir = -1;
105 static int hf_mgcp_param_localconnoptions_rsh = -1;
106 static int hf_mgcp_param_connectionmode = -1;
107 static int hf_mgcp_param_reqevents = -1;
108 static int hf_mgcp_param_restartmethod = -1;
109 static int hf_mgcp_param_restartdelay = -1;
110 static int hf_mgcp_param_signalreq = -1;
111 static int hf_mgcp_param_digitmap = -1;
112 static int hf_mgcp_param_observedevent = -1;
113 static int hf_mgcp_param_connectionparam = -1;
114 static int hf_mgcp_param_connectionparam_ps = -1;
115 static int hf_mgcp_param_connectionparam_os = -1;
116 static int hf_mgcp_param_connectionparam_pr = -1;
117 static int hf_mgcp_param_connectionparam_or = -1;
118 static int hf_mgcp_param_connectionparam_pl = -1;
119 static int hf_mgcp_param_connectionparam_ji = -1;
120 static int hf_mgcp_param_connectionparam_la = -1;
121 static int hf_mgcp_param_connectionparam_pcrps = -1;
122 static int hf_mgcp_param_connectionparam_pcros = -1;
123 static int hf_mgcp_param_connectionparam_pcrpl = -1;
124 static int hf_mgcp_param_connectionparam_pcrji = -1;
125 static int hf_mgcp_param_connectionparam_x = -1;
126 static int hf_mgcp_param_reasoncode = -1;
127 static int hf_mgcp_param_eventstates = -1;
128 static int hf_mgcp_param_specificendpoint = -1;
129 static int hf_mgcp_param_secondendpointid = -1;
130 static int hf_mgcp_param_reqinfo = -1;
131 static int hf_mgcp_param_quarantinehandling = -1;
132 static int hf_mgcp_param_detectedevents = -1;
133 static int hf_mgcp_param_capabilities = -1;
134 static int hf_mgcp_param_maxmgcpdatagram = -1;
135 static int hf_mgcp_param_packagelist = -1;
136 static int hf_mgcp_param_extension = -1;
137 static int hf_mgcp_param_extension_critical = -1;
138 static int hf_mgcp_param_invalid = -1;
139 static int hf_mgcp_messagecount = -1;
140 static int hf_mgcp_dup = -1;
141 static int hf_mgcp_req_dup = -1;
142 static int hf_mgcp_req_dup_frame = -1;
143 static int hf_mgcp_rsp_dup = -1;
144 static int hf_mgcp_rsp_dup_frame = -1;
146 static const value_string mgcp_return_code_vals[] = {
147 {000, "Response Acknowledgement"},
148 {100, "The transaction is currently being executed. An actual completion message will follow on later."},
149 {101, "The transaction has been queued for execution. An actual completion message will follow later."},
150 {200, "The requested transaction was executed normally."},
151 {250, "The connection was deleted."},
152 {400, "The transaction could not be executed, due to a transient error."},
153 {401, "The phone is already off hook"},
154 {402, "The phone is already on hook"},
155 {403, "The transaction could not be executed, because the endpoint does not have sufficient resources at this time"},
156 {404, "Insufficient bandwidth at this time"},
157 {405, "The transaction could not be executed, because the endpoint is \"restarting\"."},
158 {406, "Transaction time-out. The transaction did not complete in a reasonable period of time and has been aborted."},
159 {407, "Transaction aborted. The transaction was aborted by some external action, e.g., a ModifyConnection command aborted by a DeleteConnection command."},
160 {409, "The transaction could not be executed because of internal overload."},
161 {410, "No endpoint available. A valid \"any of\" wildcard was used, however there was no endpoint available to satisfy the request."},
162 {500, "The transaction could not be executed, because the endpoint is unknown."},
163 {501, "The transaction could not be executed, because the endpoint is not ready."},
164 {502, "The transaction could not be executed, because the endpoint does not have sufficient resources"},
165 {503, "\"All of\" wildcard too complicated."},
166 {504, "Unknown or unsupported command."},
167 {505, "Unsupported RemoteConnectionDescriptor."},
168 {506, "Unable to satisfy both LocalConnectionOptions and RemoteConnectionDescriptor."},
169 {507, "Unsupported functionality."},
170 {508, "Unknown or unsupported quarantine handling."},
171 {509, "Error in RemoteConnectionDescriptor."},
172 {510, "The transaction could not be executed, because a protocol error was detected."},
173 {511, "The transaction could not be executed, because the command contained an unrecognized extension."},
174 {512, "The transaction could not be executed, because the gateway is not equipped to detect one of the requested events."},
175 {513, "The transaction could not be executed, because the gateway is not equipped to generate one of the requested signals."},
176 {514, "The transaction could not be executed, because the gateway cannot send the specified announcement."},
177 {515, "The transaction refers to an incorrect connection-id (may have been already deleted)"},
178 {516, "The transaction refers to an unknown call-id."},
179 {517, "Unsupported or invalid mode."},
180 {518, "Unsupported or unknown package."},
181 {519, "Endpoint does not have a digit map."},
182 {520, "The transaction could not be executed, because the endpoint is 'restarting'."},
183 {521, "Endpoint redirected to another Call Agent."},
184 {522, "No such event or signal."},
185 {523, "Unknown action or illegal combination of actions"},
186 {524, "Internal inconsistency in LocalConnectionOptions"},
187 {525, "Unknown extension in LocalConnectionOptions"},
188 {526, "Insufficient bandwidth"},
189 {527, "Missing RemoteConnectionDescriptor"},
190 {528, "Incompatible protocol version"},
191 {529, "Internal hardware failure"},
192 {530, "CAS signaling protocol error."},
193 {531, "failure of a grouping of trunks (e.g. facility failure)."},
194 {532, "Unsupported value(s) in LocalConnectionOptions."},
195 {533, "Response too large."},
196 {534, "Codec negotiation failure."},
197 {535, "Packetization period not supported"},
198 {536, "Unknown or unsupported RestartMethod"},
199 {537, "Unknown or unsupported digit map extension"},
200 {538, "Event/signal parameter error (e.g., missing, erroneous, unsupported, unknown, etc.)"},
201 {539, "Invalid or unsupported command parameter."},
202 {540, "Per endpoint connection limit exceeded."},
203 {541, "Invalid or unsupported LocalConnectionOptions"},
207 /* TODO: add/use when tested/have capture to test with */
209 static const value_string mgcp_reason_code_vals[] = {
210 {0, "Endpoint state is normal"},
211 {900, "Endpoint malfunctioning."},
212 {901, "Endpoint taken out-of-service."},
213 {902, "Loss of lower layer connectivity (e.g., downstream sync)."},
214 {903, "QoS resource reservation was lost."},
215 {904, "Manual intervention."},
216 {905, "Facility failure (e.g., DS-0 failure)."},
223 * Define the trees for mgcp
224 * We need one for MGCP itself, one for the MGCP paramters and one
225 * for each of the dissected parameters
227 static int ett_mgcp = -1;
228 static int ett_mgcp_param = -1;
229 static int ett_mgcp_param_connectionparam = -1;
230 static int ett_mgcp_param_localconnectionoptions = -1;
233 * Define the tap for mgcp
235 static int mgcp_tap = -1;
238 * Here are the global variables associated with
239 * the various user definable characteristics of the dissection
241 * MGCP has two kinds of "agents", gateways and callagents. Callagents
242 * control gateways in a master/slave sort of arrangement. Since gateways
243 * and callagents have different well known ports and could both
244 * operate under either udp or tcp we have rather a lot of port info to
247 * global_mgcp_raw_text determines whether we are going to display
248 * the raw text of the mgcp message, much like the HTTP dissector does.
251 static guint global_mgcp_gateway_tcp_port = TCP_PORT_MGCP_GATEWAY;
252 static guint global_mgcp_gateway_udp_port = UDP_PORT_MGCP_GATEWAY;
253 static guint global_mgcp_callagent_tcp_port = TCP_PORT_MGCP_CALLAGENT;
254 static guint global_mgcp_callagent_udp_port = UDP_PORT_MGCP_CALLAGENT;
255 static gboolean global_mgcp_raw_text = FALSE;
256 static gboolean global_mgcp_message_count = FALSE;
258 /* Some basic utility functions that are specific to this dissector */
259 static gboolean is_mgcp_verb(tvbuff_t *tvb, gint offset, gint maxlength, const gchar **verb_name);
260 static gboolean is_mgcp_rspcode(tvbuff_t *tvb, gint offset, gint maxlength);
261 static gint tvb_parse_param(tvbuff_t *tvb, gint offset, gint maxlength, int** hf);
264 * The various functions that either dissect some
265 * subpart of MGCP. These aren't really proto dissectors but they
266 * are written in the same style.
268 static void dissect_mgcp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
269 proto_tree *mgcp_tree, proto_tree *ti);
270 static void dissect_mgcp_firstline(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
271 static void dissect_mgcp_params(tvbuff_t *tvb, proto_tree *tree);
272 static void dissect_mgcp_connectionparams(proto_tree *parent_tree, tvbuff_t *tvb,
273 gint offset, gint param_type_len,
275 static void dissect_mgcp_localconnectionoptions(proto_tree *parent_tree, tvbuff_t *tvb,
276 gint offset, gint param_type_len,
280 static void mgcp_raw_text_add(tvbuff_t *tvb, proto_tree *tree);
283 * Some functions which should be moved to a library
284 * as I think that people may find them of general usefulness.
286 static gint tvb_find_null_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset);
287 static gint tvb_find_dot_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset);
288 static gboolean is_rfc2234_alpha(guint8 c);
290 static dissector_handle_t sdp_handle;
291 static dissector_handle_t mgcp_handle;
293 dissect_asciitpkt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
294 dissector_handle_t subdissector_handle);
295 extern guint16 is_asciitpkt(tvbuff_t *tvb);
298 * Init Hash table stuff
301 typedef struct _mgcp_call_info_key
304 conversation_t *conversation;
305 } mgcp_call_info_key;
307 static GHashTable *mgcp_calls;
310 static gint mgcp_call_equal(gconstpointer k1, gconstpointer k2)
312 const mgcp_call_info_key* key1 = (const mgcp_call_info_key*) k1;
313 const mgcp_call_info_key* key2 = (const mgcp_call_info_key*) k2;
315 return (key1->transid == key2->transid &&
316 key1->conversation == key2->conversation);
319 /* Calculate a hash key */
320 static guint mgcp_call_hash(gconstpointer k)
322 const mgcp_call_info_key* key = (const mgcp_call_info_key*) k;
324 return key->transid + key->conversation->index;
328 /************************************************************************
329 * dissect_mgcp - The dissector for the Media Gateway Control Protocol
330 ************************************************************************/
331 static int dissect_mgcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
334 guint32 num_messages;
335 gint tvb_sectionend,tvb_sectionbegin, tvb_len;
336 proto_tree *mgcp_tree, *ti;
337 const gchar *verb_name = "";
339 /* Initialize variables */
341 tvb_sectionbegin = tvb_sectionend;
343 tvb_len = tvb_length(tvb);
349 * Check to see whether we're really dealing with MGCP by looking
350 * for a valid MGCP verb or response code. This isn't infallible,
351 * but its cheap and its better than nothing.
353 if (is_mgcp_verb(tvb,0,tvb_len, &verb_name) || is_mgcp_rspcode(tvb,0,tvb_len))
356 * Set the columns now, so that they'll be set correctly if we throw
357 * an exception. We can set them later as well....
359 col_set_str(pinfo->cinfo, COL_PROTOCOL, "MGCP");
360 col_clear(pinfo->cinfo, COL_INFO);
363 * Loop through however many mgcp messages may be stuck in
364 * this packet using piggybacking
371 /* Create our mgcp subtree */
372 ti = proto_tree_add_item(tree,proto_mgcp,tvb,0,0, FALSE);
373 mgcp_tree = proto_item_add_subtree(ti, ett_mgcp);
376 sectionlen = tvb_find_dot_line(tvb, tvb_sectionbegin, -1, &tvb_sectionend);
377 if (sectionlen != -1)
379 dissect_mgcp_message(tvb_new_subset(tvb, tvb_sectionbegin,
381 pinfo, tree, mgcp_tree,ti);
382 tvb_sectionbegin = tvb_sectionend;
388 } while (tvb_sectionend < tvb_len);
392 proto_item *tii = proto_tree_add_uint(mgcp_tree, hf_mgcp_messagecount, tvb,
393 0 ,0 , num_messages);
394 PROTO_ITEM_SET_HIDDEN(tii);
398 * Add our column information after dissecting SDP
399 * in order to prevent the column info changing to reflect the SDP
400 * (when showing message count)
402 tvb_sectionbegin = 0;
403 if (global_mgcp_message_count == TRUE )
405 if (num_messages > 1)
407 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "MGCP (%i messages)",num_messages);
411 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "MGCP (%i message)",num_messages);
415 sectionlen = tvb_find_line_end(tvb, tvb_sectionbegin,-1,
416 &tvb_sectionend,FALSE);
417 col_prepend_fstr(pinfo->cinfo, COL_INFO, "%s",
418 tvb_format_text(tvb, tvb_sectionbegin, sectionlen));
425 /************************************************************************
426 * dissect_tpkt_mgcp - The dissector for the ASCII TPKT Media Gateway Control Protocol
427 ************************************************************************/
428 static int dissect_tpkt_mgcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
433 /* Check whether this looks like a ASCII TPKT-encapsulated
436 ascii_tpkt = is_asciitpkt(tvb);
438 if (ascii_tpkt != 1 )
441 * It's not a ASCII TPKT packet
444 offset = dissect_mgcp(tvb, pinfo, tree);
449 * Dissect ASCII TPKT header
451 dissect_asciitpkt(tvb, pinfo, tree, mgcp_handle);
452 offset = tvb_length(tvb);
458 #define MAX_MGCP_MESSAGES_IN_PACKET 5
459 static mgcp_info_t pi_arr[MAX_MGCP_MESSAGES_IN_PACKET];
460 static int pi_current = 0;
461 static mgcp_info_t *mi;
463 /* Dissect an individual MGCP message */
464 static void dissect_mgcp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
465 proto_tree *mgcp_tree, proto_tree *ti)
467 /* Declare variables */
469 gint tvb_sectionend,tvb_sectionbegin, tvb_len;
471 const gchar *verb_name = "";
473 /* Initialise stat info for passing to tap */
475 if (pi_current == MAX_MGCP_MESSAGES_IN_PACKET)
477 /* Overwrite info in first struct if run out of space... */
480 mi = &pi_arr[pi_current];
483 mi->mgcp_type = MGCP_OTHERS;
486 mi->req_time.secs = 0;
487 mi->req_time.nsecs = 0;
488 mi->is_duplicate = FALSE;
489 mi->request_available = FALSE;
491 mi->endpointId = NULL;
492 mi->observedEvents = NULL;
494 mi->signalReq = NULL;
495 mi->hasDigitMap = FALSE;
497 /* Initialize variables */
499 tvb_sectionbegin = tvb_sectionend;
501 tvb_len = tvb_length(tvb);
504 * Check to see whether we're really dealing with MGCP by looking
505 * for a valid MGCP verb or response code. This isn't infallible,
506 * but its cheap and its better than nothing.
508 if (is_mgcp_verb(tvb,0,tvb_len,&verb_name) || is_mgcp_rspcode(tvb,0,tvb_len))
510 /* dissect first line */
511 tvb_sectionbegin = 0;
512 tvb_sectionend = tvb_sectionbegin;
513 sectionlen = tvb_find_line_end(tvb,0,-1,&tvb_sectionend,FALSE);
516 dissect_mgcp_firstline(tvb_new_subset(tvb, tvb_sectionbegin,
517 sectionlen,-1), pinfo,
520 tvb_sectionbegin = tvb_sectionend;
523 if (tvb_sectionbegin < tvb_len)
525 sectionlen = tvb_find_null_line(tvb, tvb_sectionbegin, -1,
529 dissect_mgcp_params(tvb_new_subset(tvb, tvb_sectionbegin, sectionlen, -1),
531 tvb_sectionbegin = tvb_sectionend;
535 /* Set the mgcp payload length correctly so we don't include any
537 sectionlen = tvb_sectionend;
538 proto_item_set_len(ti,sectionlen);
540 /* Display the raw text of the mgcp message if desired */
542 /* Do we want to display the raw text of our MGCP packet? */
543 if (global_mgcp_raw_text)
546 mgcp_raw_text_add(tvb, mgcp_tree);
549 /* Dissect sdp payload */
550 if (tvb_sectionend < tvb_len)
552 next_tvb = tvb_new_subset_remaining(tvb, tvb_sectionend);
553 call_dissector(sdp_handle, next_tvb, pinfo, tree);
560 * Add the raw text of the message to the dissect tree if appropriate
561 * preferences are specified.
563 static void mgcp_raw_text_add(tvbuff_t *tvb, proto_tree *tree)
565 gint tvb_linebegin,tvb_lineend,tvb_len,linelen;
568 tvb_len = tvb_length(tvb);
572 tvb_find_line_end(tvb,tvb_linebegin,-1,&tvb_lineend,FALSE);
573 linelen = tvb_lineend - tvb_linebegin;
574 proto_tree_add_text(tree, tvb, tvb_linebegin, linelen, "%s",
575 tvb_format_text(tvb, tvb_linebegin, linelen));
576 tvb_linebegin = tvb_lineend;
577 } while (tvb_lineend < tvb_len);
580 /* Discard and init any state we've saved */
581 static void mgcp_init_protocol(void)
583 if (mgcp_calls != NULL)
585 g_hash_table_destroy(mgcp_calls);
589 mgcp_calls = g_hash_table_new(mgcp_call_hash, mgcp_call_equal);
592 /* Register all the bits needed with the filtering engine */
593 void proto_register_mgcp(void)
595 static hf_register_info hf[] =
598 { "Request", "mgcp.req", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
599 "True if MGCP request", HFILL }},
601 { "Response", "mgcp.rsp", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
602 "TRUE if MGCP response", HFILL }},
603 { &hf_mgcp_req_frame,
604 { "Request Frame", "mgcp.reqframe", FT_FRAMENUM, BASE_NONE, NULL, 0,
606 { &hf_mgcp_rsp_frame,
607 { "Response Frame", "mgcp.rspframe", FT_FRAMENUM, BASE_NONE, NULL, 0,
610 { "Time from request", "mgcp.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0,
611 "Timedelta between Request and Response", HFILL }},
613 { "Verb", "mgcp.req.verb", FT_STRING, BASE_NONE, NULL, 0x0,
614 "Name of the verb", HFILL }},
615 { &hf_mgcp_req_endpoint,
616 { "Endpoint", "mgcp.req.endpoint", FT_STRING, BASE_NONE, NULL, 0x0,
617 "Endpoint referenced by the message", HFILL }},
619 { "Transaction ID", "mgcp.transid", FT_STRING, BASE_NONE, NULL, 0x0,
620 "Transaction ID of this message", HFILL }},
622 { "Version", "mgcp.version", FT_STRING, BASE_NONE, NULL, 0x0,
623 "MGCP Version", HFILL }},
624 { &hf_mgcp_rsp_rspcode,
625 { "Response Code", "mgcp.rsp.rspcode", FT_UINT32, BASE_DEC, VALS(mgcp_return_code_vals), 0x0,
627 { &hf_mgcp_rsp_rspstring,
628 { "Response String", "mgcp.rsp.rspstring", FT_STRING, BASE_NONE, NULL, 0x0,
631 { "Parameters", "mgcp.params", FT_NONE, BASE_NONE, NULL, 0x0,
632 "MGCP parameters", HFILL }},
633 { &hf_mgcp_param_rspack,
634 { "ResponseAck (K)", "mgcp.param.rspack", FT_STRING, BASE_NONE, NULL, 0x0,
635 "Response Ack", HFILL }},
636 { &hf_mgcp_param_bearerinfo,
637 { "BearerInformation (B)", "mgcp.param.bearerinfo", FT_STRING, BASE_NONE, NULL, 0x0,
638 "Bearer Information", HFILL }},
639 { &hf_mgcp_param_callid,
640 { "CallId (C)", "mgcp.param.callid", FT_STRING, BASE_NONE, NULL, 0x0,
642 { &hf_mgcp_param_connectionid,
643 {"ConnectionIdentifier (I)", "mgcp.param.connectionid", FT_STRING, BASE_NONE, NULL, 0x0,
644 "Connection Identifier", HFILL }},
645 { &hf_mgcp_param_secondconnectionid,
646 { "SecondConnectionID (I2)", "mgcp.param.secondconnectionid", FT_STRING, BASE_NONE, NULL, 0x0,
647 "Second Connection Identifier", HFILL }},
648 { &hf_mgcp_param_notifiedentity,
649 { "NotifiedEntity (N)", "mgcp.param.notifiedentity", FT_STRING, BASE_NONE, NULL, 0x0,
650 "Notified Entity", HFILL }},
651 { &hf_mgcp_param_requestid,
652 { "RequestIdentifier (X)", "mgcp.param.requestid", FT_STRING, BASE_NONE, NULL, 0x0,
653 "Request Identifier", HFILL }},
654 { &hf_mgcp_param_localconnoptions,
655 { "LocalConnectionOptions (L)", "mgcp.param.localconnectionoptions", FT_STRING, BASE_NONE, NULL, 0x0,
656 "Local Connection Options", HFILL }},
657 { &hf_mgcp_param_localconnoptions_p,
658 { "Packetization period (p)", "mgcp.param.localconnectionoptions.p", FT_UINT32, BASE_DEC, NULL, 0x0,
659 "Packetization period", HFILL }},
660 { &hf_mgcp_param_localconnoptions_a,
661 { "Codecs (a)", "mgcp.param.localconnectionoptions.a", FT_STRING, BASE_NONE, NULL, 0x0,
663 { &hf_mgcp_param_localconnoptions_s,
664 { "Silence Suppression (s)", "mgcp.param.localconnectionoptions.s", FT_STRING, BASE_NONE, NULL, 0x0,
665 "Silence Suppression", HFILL }},
666 { &hf_mgcp_param_localconnoptions_e,
667 { "Echo Cancellation (e)", "mgcp.param.localconnectionoptions.e", FT_STRING, BASE_NONE, NULL, 0x0,
668 "Echo Cancellation", HFILL }},
669 { &hf_mgcp_param_localconnoptions_scrtp,
670 { "RTP ciphersuite (sc-rtp)", "mgcp.param.localconnectionoptions.scrtp", FT_STRING, BASE_NONE, NULL, 0x0,
671 "RTP ciphersuite", HFILL }},
672 { &hf_mgcp_param_localconnoptions_scrtcp,
673 { "RTCP ciphersuite (sc-rtcp)", "mgcp.param.localconnectionoptions.scrtcp", FT_STRING, BASE_NONE, NULL, 0x0,
674 "RTCP ciphersuite", HFILL }},
675 { &hf_mgcp_param_localconnoptions_b,
676 { "Bandwidth (b)", "mgcp.param.localconnectionoptions.b", FT_STRING, BASE_NONE, NULL, 0x0,
677 "Bandwidth", HFILL }},
678 { &hf_mgcp_param_localconnoptions_esccd,
679 { "Content Destination (es-ccd)", "mgcp.param.localconnectionoptions.esccd", FT_STRING, BASE_NONE, NULL, 0x0,
680 "Content Destination", HFILL }},
681 { &hf_mgcp_param_localconnoptions_escci,
682 { "Content Identifier (es-cci)", "mgcp.param.localconnectionoptions.escci", FT_STRING, BASE_NONE, NULL, 0x0,
683 "Content Identifier", HFILL }},
684 { &hf_mgcp_param_localconnoptions_dqgi,
685 { "D-QoS GateID (dq-gi)", "mgcp.param.localconnectionoptions.dqgi", FT_STRING, BASE_NONE, NULL, 0x0,
686 "D-QoS GateID", HFILL }},
687 { &hf_mgcp_param_localconnoptions_dqrd,
688 { "D-QoS Reserve Destination (dq-rd)", "mgcp.param.localconnectionoptions.dqrd", FT_STRING, BASE_NONE, NULL, 0x0,
689 "D-QoS Reserve Destination", HFILL }},
690 { &hf_mgcp_param_localconnoptions_dqri,
691 { "D-QoS Resource ID (dq-ri)", "mgcp.param.localconnectionoptions.dqri", FT_STRING, BASE_NONE, NULL, 0x0,
692 "D-QoS Resource ID", HFILL }},
693 { &hf_mgcp_param_localconnoptions_dqrr,
694 { "D-QoS Resource Reservation (dq-rr)", "mgcp.param.localconnectionoptions.dqrr", FT_STRING, BASE_NONE, NULL, 0x0,
695 "D-QoS Resource Reservation", HFILL }},
696 { &hf_mgcp_param_localconnoptions_k,
697 { "Encryption Key (k)", "mgcp.param.localconnectionoptions.k", FT_STRING, BASE_NONE, NULL, 0x0,
698 "Encryption Key", HFILL }},
699 { &hf_mgcp_param_localconnoptions_gc,
700 { "Gain Control (gc)", "mgcp.param.localconnectionoptions.gc", FT_UINT32, BASE_DEC, NULL, 0x0,
701 "Gain Control", HFILL }},
702 { &hf_mgcp_param_localconnoptions_fmtp,
703 { "Media Format (fmtp)", "mgcp.param.localconnectionoptions.fmtp", FT_STRING, BASE_NONE, NULL, 0x0,
704 "Media Format", HFILL }},
705 { &hf_mgcp_param_localconnoptions_nt,
706 { "Network Type (nt)", "mgcp.param.localconnectionoptions.nt", FT_STRING, BASE_NONE, NULL, 0x0,
707 "Network Type", HFILL }},
708 { &hf_mgcp_param_localconnoptions_ofmtp,
709 { "Optional Media Format (o-fmtp)", "mgcp.param.localconnectionoptions.ofmtp", FT_STRING, BASE_NONE, NULL, 0x0,
710 "Optional Media Format", HFILL }},
711 { &hf_mgcp_param_localconnoptions_r,
712 { "Resource Reservation (r)", "mgcp.param.localconnectionoptions.r", FT_STRING, BASE_NONE, NULL, 0x0,
713 "Resource Reservation", HFILL }},
714 { &hf_mgcp_param_localconnoptions_t,
715 { "Type of Service (r)", "mgcp.param.localconnectionoptions.t", FT_STRING, BASE_NONE, NULL, 0x0,
716 "Type of Service", HFILL }},
717 { &hf_mgcp_param_localconnoptions_rcnf,
718 { "Reservation Confirmation (r-cnf)", "mgcp.param.localconnectionoptions.rcnf", FT_STRING, BASE_NONE, NULL, 0x0,
719 "Reservation Confirmation", HFILL }},
720 { &hf_mgcp_param_localconnoptions_rdir,
721 { "Reservation Direction (r-dir)", "mgcp.param.localconnectionoptions.rdir", FT_STRING, BASE_NONE, NULL, 0x0,
722 "Reservation Direction", HFILL }},
723 { &hf_mgcp_param_localconnoptions_rsh,
724 { "Resource Sharing (r-sh)", "mgcp.param.localconnectionoptions.rsh", FT_STRING, BASE_NONE, NULL, 0x0,
725 "Resource Sharing", HFILL }},
726 { &hf_mgcp_param_connectionmode,
727 { "ConnectionMode (M)", "mgcp.param.connectionmode", FT_STRING, BASE_NONE, NULL, 0x0,
728 "Connection Mode", HFILL }},
729 { &hf_mgcp_param_reqevents,
730 { "RequestedEvents (R)", "mgcp.param.reqevents", FT_STRING, BASE_NONE, NULL, 0x0,
731 "Requested Events", HFILL }},
732 { &hf_mgcp_param_signalreq,
733 { "SignalRequests (S)", "mgcp.param.signalreq", FT_STRING, BASE_NONE, NULL, 0x0,
734 "Signal Request", HFILL }},
735 { &hf_mgcp_param_restartmethod,
736 { "RestartMethod (RM)", "mgcp.param.restartmethod", FT_STRING, BASE_NONE, NULL, 0x0,
737 "Restart Method", HFILL }},
738 { &hf_mgcp_param_restartdelay,
739 { "RestartDelay (RD)", "mgcp.param.restartdelay", FT_STRING, BASE_NONE, NULL, 0x0,
740 "Restart Delay", HFILL }},
741 { &hf_mgcp_param_digitmap,
742 { "DigitMap (D)", "mgcp.param.digitmap", FT_STRING, BASE_NONE, NULL, 0x0,
743 "Digit Map", HFILL }},
744 { &hf_mgcp_param_observedevent,
745 { "ObservedEvents (O)", "mgcp.param.observedevents", FT_STRING, BASE_NONE, NULL, 0x0,
746 "Observed Events", HFILL }},
747 { &hf_mgcp_param_connectionparam,
748 { "ConnectionParameters (P)", "mgcp.param.connectionparam", FT_STRING, BASE_NONE, NULL, 0x0,
749 "Connection Parameters", HFILL }},
750 { &hf_mgcp_param_connectionparam_ps,
751 { "Packets sent (PS)", "mgcp.param.connectionparam.ps", FT_UINT32, BASE_DEC, NULL, 0x0,
752 "Packets sent (P:PS)", HFILL }},
753 { &hf_mgcp_param_connectionparam_os,
754 { "Octets sent (OS)", "mgcp.param.connectionparam.os", FT_UINT32, BASE_DEC, NULL, 0x0,
755 "Octets sent (P:OS)", HFILL }},
756 { &hf_mgcp_param_connectionparam_pr,
757 { "Packets received (PR)", "mgcp.param.connectionparam.pr", FT_UINT32, BASE_DEC, NULL, 0x0,
758 "Packets received (P:PR)", HFILL }},
759 { &hf_mgcp_param_connectionparam_or,
760 { "Octets received (OR)", "mgcp.param.connectionparam.or", FT_UINT32, BASE_DEC, NULL, 0x0,
761 "Octets received (P:OR)", HFILL }},
762 { &hf_mgcp_param_connectionparam_pl,
763 { "Packets lost (PL)", "mgcp.param.connectionparam.pl", FT_UINT32, BASE_DEC, NULL, 0x0,
764 "Packets lost (P:PL)", HFILL }},
765 { &hf_mgcp_param_connectionparam_ji,
766 { "Jitter (JI)", "mgcp.param.connectionparam.ji", FT_UINT32, BASE_DEC, NULL, 0x0,
767 "Average inter-packet arrival jitter in milliseconds (P:JI)", HFILL }},
768 { &hf_mgcp_param_connectionparam_la,
769 { "Latency (LA)", "mgcp.param.connectionparam.la", FT_UINT32, BASE_DEC, NULL, 0x0,
770 "Average latency in milliseconds (P:LA)", HFILL }},
771 { &hf_mgcp_param_connectionparam_pcrps,
772 { "Remote Packets sent (PC/RPS)", "mgcp.param.connectionparam.pcrps", FT_UINT32, BASE_DEC, NULL, 0x0,
773 "Remote Packets sent (P:PC/RPS)", HFILL }},
774 { &hf_mgcp_param_connectionparam_pcros,
775 { "Remote Octets sent (PC/ROS)", "mgcp.param.connectionparam.pcros", FT_UINT32, BASE_DEC, NULL, 0x0,
776 "Remote Octets sent (P:PC/ROS)", HFILL }},
777 { &hf_mgcp_param_connectionparam_pcrpl,
778 { "Remote Packets lost (PC/RPL)", "mgcp.param.connectionparam.pcrpl", FT_UINT32, BASE_DEC, NULL, 0x0,
779 "Remote Packets lost (P:PC/RPL)", HFILL }},
780 { &hf_mgcp_param_connectionparam_pcrji,
781 { "Remote Jitter (PC/RJI)", "mgcp.param.connectionparam.pcrji", FT_UINT32, BASE_DEC, NULL, 0x0,
782 "Remote Jitter (P:PC/RJI)", HFILL }},
783 { &hf_mgcp_param_connectionparam_x,
784 { "Vendor Extension", "mgcp.param.connectionparam.x", FT_STRING, BASE_NONE, NULL, 0x0,
785 "Vendor Extension (P:X-*)", HFILL }},
786 { &hf_mgcp_param_reasoncode,
787 { "ReasonCode (E)", "mgcp.param.reasoncode", FT_STRING, BASE_NONE, NULL, 0x0,
788 "Reason Code", HFILL }},
789 { &hf_mgcp_param_eventstates,
790 { "EventStates (ES)", "mgcp.param.eventstates", FT_STRING, BASE_NONE, NULL, 0x0,
791 "Event States", HFILL }},
792 { &hf_mgcp_param_specificendpoint,
793 { "SpecificEndpointID (Z)", "mgcp.param.specificendpointid", FT_STRING, BASE_NONE, NULL, 0x0,
794 "Specific Endpoint ID", HFILL }},
795 { &hf_mgcp_param_secondendpointid,
796 { "SecondEndpointID (Z2)", "mgcp.param.secondendpointid", FT_STRING, BASE_NONE, NULL, 0x0,
797 "Second Endpoint ID", HFILL }},
798 { &hf_mgcp_param_reqinfo,
799 { "RequestedInfo (F)", "mgcp.param.reqinfo", FT_STRING, BASE_NONE, NULL, 0x0,
800 "Requested Info", HFILL }},
801 { &hf_mgcp_param_quarantinehandling,
802 { "QuarantineHandling (Q)", "mgcp.param.quarantinehandling", FT_STRING, BASE_NONE, NULL, 0x0,
803 "Quarantine Handling", HFILL }},
804 { &hf_mgcp_param_detectedevents,
805 { "DetectedEvents (T)", "mgcp.param.detectedevents", FT_STRING, BASE_NONE, NULL, 0x0,
806 "Detected Events", HFILL }},
807 { &hf_mgcp_param_capabilities,
808 { "Capabilities (A)", "mgcp.param.capabilities", FT_STRING, BASE_NONE, NULL, 0x0,
809 "Capabilities", HFILL }},
810 { &hf_mgcp_param_maxmgcpdatagram,
811 {"MaxMGCPDatagram (MD)", "mgcp.param.maxmgcpdatagram", FT_STRING, BASE_NONE, NULL, 0x0,
812 "Maximum MGCP Datagram size", HFILL }},
813 { &hf_mgcp_param_packagelist,
814 {"PackageList (PL)", "mgcp.param.packagelist", FT_STRING, BASE_NONE, NULL, 0x0,
815 "Package List", HFILL }},
816 { &hf_mgcp_param_extension,
817 { "Extension Parameter (non-critical)", "mgcp.param.extension", FT_STRING, BASE_NONE, NULL, 0x0,
818 "Extension Parameter", HFILL }},
819 { &hf_mgcp_param_extension_critical,
820 { "Extension Parameter (critical)", "mgcp.param.extensioncritical", FT_STRING, BASE_NONE, NULL, 0x0,
821 "Critical Extension Parameter", HFILL }},
822 { &hf_mgcp_param_invalid,
823 { "Invalid Parameter", "mgcp.param.invalid", FT_STRING, BASE_NONE, NULL, 0x0,
825 { &hf_mgcp_messagecount,
826 { "MGCP Message Count", "mgcp.messagecount", FT_UINT32, BASE_DEC, NULL, 0x0,
827 "Number of MGCP message in a packet", HFILL }},
829 { "Duplicate Message", "mgcp.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
832 { "Duplicate Request", "mgcp.req.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
834 { &hf_mgcp_req_dup_frame,
835 { "Original Request Frame", "mgcp.req.dup.frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
836 "Frame containing original request", HFILL }},
838 { "Duplicate Response", "mgcp.rsp.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
840 { &hf_mgcp_rsp_dup_frame,
841 { "Original Response Frame", "mgcp.rsp.dup.frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
842 "Frame containing original response", HFILL }},
849 &ett_mgcp_param_connectionparam,
850 &ett_mgcp_param_localconnectionoptions
853 module_t *mgcp_module;
855 /* Register protocol */
856 proto_mgcp = proto_register_protocol("Media Gateway Control Protocol", "MGCP", "mgcp");
857 proto_register_field_array(proto_mgcp, hf, array_length(hf));
858 proto_register_subtree_array(ett, array_length(ett));
859 register_init_routine(&mgcp_init_protocol);
861 new_register_dissector("mgcp", dissect_mgcp, proto_mgcp);
863 /* Register our configuration options */
864 mgcp_module = prefs_register_protocol(proto_mgcp, proto_reg_handoff_mgcp);
866 prefs_register_uint_preference(mgcp_module, "tcp.gateway_port",
867 "MGCP Gateway TCP Port",
868 "Set the UDP port for gateway messages "
869 "(if other than the default of 2427)",
870 10, &global_mgcp_gateway_tcp_port);
872 prefs_register_uint_preference(mgcp_module, "udp.gateway_port",
873 "MGCP Gateway UDP Port",
874 "Set the TCP port for gateway messages "
875 "(if other than the default of 2427)",
876 10, &global_mgcp_gateway_udp_port);
878 prefs_register_uint_preference(mgcp_module, "tcp.callagent_port",
879 "MGCP Callagent TCP Port",
880 "Set the TCP port for callagent messages "
881 "(if other than the default of 2727)",
882 10, &global_mgcp_callagent_tcp_port);
884 prefs_register_uint_preference(mgcp_module, "udp.callagent_port",
885 "MGCP Callagent UDP Port",
886 "Set the UDP port for callagent messages "
887 "(if other than the default of 2727)",
888 10, &global_mgcp_callagent_udp_port);
891 prefs_register_bool_preference(mgcp_module, "display_raw_text",
892 "Display raw text for MGCP message",
893 "Specifies that the raw text of the "
894 "MGCP message should be displayed "
895 "instead of (or in addition to) the "
897 &global_mgcp_raw_text);
899 prefs_register_obsolete_preference(mgcp_module, "display_dissect_tree");
901 prefs_register_bool_preference(mgcp_module, "display_mgcp_message_count",
902 "Display the number of MGCP messages",
903 "Display the number of MGCP messages "
904 "found in a packet in the protocol column.",
905 &global_mgcp_message_count);
907 mgcp_tap = register_tap("mgcp");
910 /* The registration hand-off routine */
911 void proto_reg_handoff_mgcp(void)
913 static gboolean mgcp_prefs_initialized = FALSE;
914 static dissector_handle_t mgcp_tpkt_handle;
916 * Variables to allow for proper deletion of dissector registration when
917 * the user changes port from the gui.
919 static guint gateway_tcp_port;
920 static guint gateway_udp_port;
921 static guint callagent_tcp_port;
922 static guint callagent_udp_port;
924 if (!mgcp_prefs_initialized)
926 /* Get a handle for the SDP dissector. */
927 sdp_handle = find_dissector("sdp");
928 mgcp_handle = new_create_dissector_handle(dissect_mgcp, proto_mgcp);
929 mgcp_tpkt_handle = new_create_dissector_handle(dissect_tpkt_mgcp, proto_mgcp);
930 mgcp_prefs_initialized = TRUE;
934 dissector_delete_uint("tcp.port", gateway_tcp_port, mgcp_tpkt_handle);
935 dissector_delete_uint("udp.port", gateway_udp_port, mgcp_handle);
936 dissector_delete_uint("tcp.port", callagent_tcp_port, mgcp_tpkt_handle);
937 dissector_delete_uint("udp.port", callagent_udp_port, mgcp_handle);
940 /* Set our port number for future use */
941 gateway_tcp_port = global_mgcp_gateway_tcp_port;
942 gateway_udp_port = global_mgcp_gateway_udp_port;
944 callagent_tcp_port = global_mgcp_callagent_tcp_port;
945 callagent_udp_port = global_mgcp_callagent_udp_port;
947 dissector_add_uint("tcp.port", global_mgcp_gateway_tcp_port, mgcp_tpkt_handle);
948 dissector_add_uint("udp.port", global_mgcp_gateway_udp_port, mgcp_handle);
949 dissector_add_uint("tcp.port", global_mgcp_callagent_tcp_port, mgcp_tpkt_handle);
950 dissector_add_uint("udp.port", global_mgcp_callagent_udp_port, mgcp_handle);
954 * is_mgcp_verb - A function for determining whether there is a
955 * MGCP verb at offset in tvb
958 * tvb - The tvbuff in which we are looking for an MGCP verb
959 * offset - The offset in tvb at which we are looking for a MGCP verb
960 * maxlength - The maximum distance from offset we may look for the
961 * characters that make up a MGCP verb.
962 * verb_name - The name for the verb code found (output)
964 * Return: TRUE if there is an MGCP verb at offset in tvb, otherwise FALSE
966 static gboolean is_mgcp_verb(tvbuff_t *tvb, gint offset, gint maxlength, const gchar **verb_name)
968 int returnvalue = FALSE;
971 /* Read the string into 'word' and see if it looks like the start of a verb */
972 if ((maxlength >= 4) && tvb_get_nstringz0(tvb, offset, sizeof(word), word))
974 if (((g_ascii_strncasecmp(word, "EPCF", 4) == 0) && (*verb_name = "EndpointConfiguration")) ||
975 ((g_ascii_strncasecmp(word, "CRCX", 4) == 0) && (*verb_name = "CreateConnection")) ||
976 ((g_ascii_strncasecmp(word, "MDCX", 4) == 0) && (*verb_name = "ModifyConnection")) ||
977 ((g_ascii_strncasecmp(word, "DLCX", 4) == 0) && (*verb_name = "DeleteConnection")) ||
978 ((g_ascii_strncasecmp(word, "RQNT", 4) == 0) && (*verb_name = "NotificationRequest")) ||
979 ((g_ascii_strncasecmp(word, "NTFY", 4) == 0) && (*verb_name = "Notify")) ||
980 ((g_ascii_strncasecmp(word, "AUEP", 4) == 0) && (*verb_name = "AuditEndpoint")) ||
981 ((g_ascii_strncasecmp(word, "AUCX", 4) == 0) && (*verb_name = "AuditConnection")) ||
982 ((g_ascii_strncasecmp(word, "RSIP", 4) == 0) && (*verb_name = "RestartInProgress")) ||
983 ((g_ascii_strncasecmp(word, "MESG", 4) == 0) && (*verb_name = "Message")) ||
984 (word[0] == 'X' && is_rfc2234_alpha(word[1]) && is_rfc2234_alpha(word[2]) &&
985 is_rfc2234_alpha(word[3]) && (*verb_name = "*Experimental*")))
991 /* May be whitespace after verb code - anything else is an error.. */
992 if (returnvalue && maxlength >= 5)
994 char next = tvb_get_guint8(tvb,4);
995 if ((next != ' ') && (next != '\t'))
1005 * is_mgcp_rspcode - A function for determining whether something which
1006 * looks roughly like a MGCP response code (3-digit number)
1007 * is at 'offset' in tvb
1010 * tvb - The tvbuff in which we are looking for an MGCP response code
1011 * offset - The offset in tvb at which we are looking for a MGCP response code
1012 * maxlength - The maximum distance from offset we may look for the
1013 * characters that make up a MGCP response code.
1015 * Return: TRUE if there is an MGCP response code at offset in tvb,
1018 static gboolean is_mgcp_rspcode(tvbuff_t *tvb, gint offset, gint maxlength)
1020 int returnvalue = FALSE;
1023 /* Do 1st 3 characters look like digits? */
1026 tvb_get_nstringz0(tvb, offset, sizeof(word), word);
1027 if (isdigit(word[0]) && isdigit(word[1]) && isdigit(word[2]))
1033 /* Maybe some white space after the 3rd digit - anything else is an error */
1034 if (returnvalue && maxlength >= 4)
1036 char next = tvb_get_guint8(tvb, 3);
1037 if ((next != ' ') && (next != '\t'))
1039 returnvalue = FALSE;
1047 * is_rfc2234_alpha - Indicates whether the character c is an alphabetical
1048 * character. This function is used instead of
1049 * isalpha because isalpha may deviate from the rfc2234
1050 * definition of ALPHA in some locales.
1053 * c - The character being checked for being an alphabetical character.
1055 * Return: TRUE if c is an upper or lower case alphabetical character,
1058 static gboolean is_rfc2234_alpha(guint8 c)
1060 return ((c <= 'Z' && c >= 'A' ) || (c <= 'z' && c >= 'a'));
1065 * tvb_parse_param - Parse the MGCP param into a type and a value.
1068 * tvb - The tvbuff containing the MGCP param we are to parse.
1069 * offset - The offset in tvb at which we will begin looking for a
1070 * MGCP parameter to parse.
1071 * len - The maximum distance from offset in tvb that we can look for
1072 * an MGCP parameter to parse.
1073 * hf - The place to write a pointer to the integer representing the
1074 * header field associated with the MGCP parameter parsed.
1076 * Returns: The offset in tvb where the value of the MGCP parameter
1079 static gint tvb_parse_param(tvbuff_t* tvb, gint offset, gint len, int** hf)
1081 gint returnvalue = -1, tvb_current_offset,counter;
1082 guint8 tempchar, plus_minus;
1085 tvb_current_offset = offset;
1091 tempchar = tvb_get_guint8(tvb,tvb_current_offset);
1096 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1098 *hf = &hf_mgcp_param_invalid;
1101 *hf = &hf_mgcp_param_rspack;
1104 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1106 *hf = &hf_mgcp_param_invalid;
1109 *hf = &hf_mgcp_param_bearerinfo;
1112 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1114 *hf = &hf_mgcp_param_invalid;
1117 *hf = &hf_mgcp_param_callid;
1120 tvb_current_offset++;
1121 if (len > (tvb_current_offset - offset) &&
1122 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1124 *hf = &hf_mgcp_param_connectionid;
1125 tvb_current_offset--;
1128 if (tempchar == '2')
1130 *hf = &hf_mgcp_param_secondconnectionid;
1134 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1136 *hf = &hf_mgcp_param_invalid;
1139 *hf = &hf_mgcp_param_notifiedentity;
1143 tvb_current_offset++;
1145 /* X: is RequestIdentifier */
1146 if (len > (tvb_current_offset - offset) &&
1147 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1149 *hf = &hf_mgcp_param_requestid;
1150 tvb_current_offset--;
1153 /* X+...: or X-....: are vendor extension parameters */
1155 if (len > (tvb_current_offset - offset) &&
1156 ((plus_minus = tvb_get_guint8(tvb,tvb_current_offset)) == '-' ||
1157 (plus_minus == '+')))
1159 /* Move past + or - */
1160 tvb_current_offset++;
1162 /* Keep going, through possible vendor param name */
1164 ((len > (counter + tvb_current_offset-offset)) &&
1165 (is_rfc2234_alpha(tempchar = tvb_get_guint8(tvb, tvb_current_offset+counter)) ||
1166 isdigit(tempchar))) ;
1169 if (tempchar == ':')
1171 /* Looks like a valid vendor param name */
1172 tvb_current_offset += counter;
1176 *hf = &hf_mgcp_param_extension_critical;
1179 *hf = &hf_mgcp_param_extension;
1186 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1188 *hf = &hf_mgcp_param_invalid;
1191 *hf = &hf_mgcp_param_localconnoptions;
1194 tvb_current_offset++;
1195 if (len > (tvb_current_offset - offset) &&
1196 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1198 *hf = &hf_mgcp_param_connectionmode;
1199 tvb_current_offset--;
1202 if (tempchar == 'D')
1204 *hf = &hf_mgcp_param_maxmgcpdatagram;
1208 tvb_current_offset++;
1209 if (len > (tvb_current_offset - offset) &&
1210 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1212 *hf = &hf_mgcp_param_reqevents;
1213 tvb_current_offset--;
1216 if ( tempchar == 'M')
1218 *hf = &hf_mgcp_param_restartmethod;
1221 if (tempchar == 'D')
1223 *hf = &hf_mgcp_param_restartdelay;
1227 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1229 *hf = &hf_mgcp_param_invalid;
1232 *hf = &hf_mgcp_param_signalreq;
1233 buf = &(mi->signalReq);
1236 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1238 *hf = &hf_mgcp_param_invalid;
1241 *hf = &hf_mgcp_param_digitmap;
1242 mi->hasDigitMap = TRUE;
1245 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1247 *hf = &hf_mgcp_param_invalid;
1250 *hf = &hf_mgcp_param_observedevent;
1251 buf = &(mi->observedEvents);
1254 tvb_current_offset++;
1255 if (len > (tvb_current_offset - offset) &&
1256 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1258 *hf = &hf_mgcp_param_connectionparam;
1259 tvb_current_offset--;
1262 if ( tempchar == 'L')
1264 *hf = &hf_mgcp_param_packagelist;
1268 tvb_current_offset++;
1269 if (len > (tvb_current_offset - offset) &&
1270 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1272 *hf = &hf_mgcp_param_reasoncode;
1273 tvb_current_offset--;
1276 if ( tempchar == 'S')
1278 *hf = &hf_mgcp_param_eventstates;
1282 tvb_current_offset++;
1283 if (len > (tvb_current_offset - offset) &&
1284 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1286 *hf = &hf_mgcp_param_specificendpoint;
1287 tvb_current_offset--;
1290 if (tempchar == '2')
1292 *hf = &hf_mgcp_param_secondendpointid;
1296 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1298 *hf = &hf_mgcp_param_invalid;
1301 *hf = &hf_mgcp_param_reqinfo;
1304 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1306 *hf = &hf_mgcp_param_invalid;
1309 *hf = &hf_mgcp_param_quarantinehandling;
1312 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1314 *hf = &hf_mgcp_param_invalid;
1317 *hf = &hf_mgcp_param_detectedevents;
1320 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1322 *hf = &hf_mgcp_param_invalid;
1325 *hf = &hf_mgcp_param_capabilities;
1329 *hf = &hf_mgcp_param_invalid;
1333 /* Move to (hopefully) the colon */
1334 tvb_current_offset++;
1336 /* Add a recognised parameter type if we have one */
1337 if (*hf != NULL && len > (tvb_current_offset - offset) &&
1338 tvb_get_guint8(tvb,tvb_current_offset) == ':')
1340 tvb_current_offset++;
1341 tvb_current_offset = tvb_skip_wsp(tvb,tvb_current_offset, (len - tvb_current_offset + offset));
1342 returnvalue = tvb_current_offset;
1344 /* set the observedEvents or signalReq used in Voip Calls analysis */
1346 *buf = tvb_get_ephemeral_string(tvb, tvb_current_offset, (len - tvb_current_offset + offset));
1352 /* Was an empty line */
1353 *hf = &hf_mgcp_param_invalid;
1356 /* For these types, show the whole line */
1357 if ((*hf == &hf_mgcp_param_invalid) ||
1358 (*hf == &hf_mgcp_param_extension) || (*hf == &hf_mgcp_param_extension_critical))
1360 returnvalue = offset;
1368 * dissect_mgcp_firstline - Dissects the firstline of an MGCP message.
1369 * Adds the appropriate headers fields to
1370 * tree for the dissection of the first line
1371 * of an MGCP message.
1374 * tvb - The tvb containing the first line of an MGCP message. This
1375 * tvb is presumed to ONLY contain the first line of the MGCP
1377 * pinfo - The packet info for the packet. This is not really used
1378 * by this function but is passed through so as to retain the
1379 * style of a dissector.
1380 * tree - The tree from which to hang the structured information parsed
1381 * from the first line of the MGCP message.
1383 static void dissect_mgcp_firstline(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1385 gint tvb_current_offset,tvb_previous_offset,tvb_len,tvb_current_len;
1386 gint tokennum, tokenlen;
1387 proto_item* hidden_item;
1388 char *transid = NULL;
1390 char *endpointId = NULL;
1391 mgcp_type_t mgcp_type = MGCP_OTHERS;
1392 conversation_t* conversation;
1393 mgcp_call_info_key mgcp_call_key;
1394 mgcp_call_info_key *new_mgcp_call_key = NULL;
1395 mgcp_call_t *mgcp_call = NULL;
1398 const gchar *verb_description = "";
1399 char code_with_verb[64] = ""; /* To fit "<4-letter-code> (<longest-verb>)" */
1401 static address null_address = { AT_NONE, 0, NULL };
1402 tvb_previous_offset = 0;
1403 tvb_len = tvb_length(tvb);
1404 tvb_current_len = tvb_len;
1405 tvb_current_offset = tvb_previous_offset;
1406 mi->is_duplicate = FALSE;
1407 mi->request_available = FALSE;
1415 tvb_current_len = tvb_length_remaining(tvb,tvb_previous_offset);
1416 tvb_current_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_current_len, ' ');
1417 if (tvb_current_offset == -1)
1419 tvb_current_offset = tvb_len;
1420 tokenlen = tvb_current_len;
1424 tokenlen = tvb_current_offset - tvb_previous_offset;
1429 THROW(ReportedBoundsError);
1430 code = tvb_format_text(tvb,tvb_previous_offset,tokenlen);
1431 g_strlcpy(mi->code,code,5);
1432 if (is_mgcp_verb(tvb,tvb_previous_offset,tvb_current_len,&verb_description))
1434 mgcp_type = MGCP_REQUEST;
1435 if (verb_description != NULL)
1437 /* Can show verb along with code if known */
1438 g_snprintf(code_with_verb, 64, "%s (%s)", code, verb_description);
1441 proto_tree_add_string_format(tree, hf_mgcp_req_verb, tvb,
1442 tvb_previous_offset, tokenlen,
1444 strlen(code_with_verb) ? code_with_verb : code);
1447 if (is_mgcp_rspcode(tvb,tvb_previous_offset,tvb_current_len))
1449 mgcp_type = MGCP_RESPONSE;
1450 rspcode = atoi(code);
1451 mi->rspcode = rspcode;
1452 proto_tree_add_uint(tree,hf_mgcp_rsp_rspcode, tvb,
1453 tvb_previous_offset, tokenlen, rspcode);
1462 transid = tvb_format_text(tvb,tvb_previous_offset,tokenlen);
1463 /* XXX - what if this isn't a valid text string? */
1464 mi->transid = atol(transid);
1465 proto_tree_add_string(tree, hf_mgcp_transid, tvb,
1466 tvb_previous_offset, tokenlen, transid);
1470 if (mgcp_type == MGCP_REQUEST)
1472 endpointId = tvb_format_text(tvb, tvb_previous_offset,tokenlen);
1473 mi->endpointId = ep_strdup(endpointId);
1474 proto_tree_add_string(tree,hf_mgcp_req_endpoint, tvb,
1475 tvb_previous_offset, tokenlen, endpointId);
1478 if (mgcp_type == MGCP_RESPONSE)
1480 if (tvb_current_offset < tvb_len)
1482 tokenlen = tvb_find_line_end(tvb, tvb_previous_offset,
1483 -1, &tvb_current_offset, FALSE);
1487 tokenlen = tvb_current_len;
1489 proto_tree_add_string(tree, hf_mgcp_rsp_rspstring, tvb,
1490 tvb_previous_offset, tokenlen,
1491 tvb_format_text(tvb, tvb_previous_offset,
1497 if ((tokennum == 3 && mgcp_type == MGCP_REQUEST))
1499 if (tvb_current_offset < tvb_len )
1501 tokenlen = tvb_find_line_end(tvb, tvb_previous_offset,
1502 -1, &tvb_current_offset,FALSE);
1506 tokenlen = tvb_current_len;
1508 proto_tree_add_string(tree,hf_mgcp_version, tvb,
1509 tvb_previous_offset, tokenlen,
1510 tvb_format_text(tvb,tvb_previous_offset,
1514 if (tvb_current_offset < tvb_len)
1516 tvb_previous_offset = tvb_skip_wsp(tvb, tvb_current_offset,
1520 } while (tvb_current_offset < tvb_len && tvb_previous_offset < tvb_len && tokennum <= 3);
1525 hidden_item = proto_tree_add_boolean(tree, hf_mgcp_rsp, tvb, 0, 0, TRUE);
1526 PROTO_ITEM_SET_HIDDEN(hidden_item);
1527 /* Check for MGCP response. A response must match a call that
1528 we've seen, and the response must be sent to the same
1529 port and address that the call came from, and must
1530 come from the port to which the call was sent.
1532 If the transport is connection-oriented (we check, for
1533 now, only for "pinfo->ptype" of PT_TCP), we take
1534 into account the address from which the call was sent
1535 and the address to which the call was sent, because
1536 the addresses of the two endpoints should be the same
1537 for all calls and replies.
1539 If the transport is connectionless, we don't worry
1540 about the address to which the call was sent and from
1541 which the reply was sent, because there's no
1542 guarantee that the reply will come from the address
1543 to which the call was sent. */
1544 if (pinfo->ptype == PT_TCP)
1546 conversation = find_conversation(pinfo->fd->num, &pinfo->src,
1547 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1548 pinfo->destport, 0);
1552 /* XXX - can we just use NO_ADDR_B? Unfortunately,
1553 * you currently still have to pass a non-null
1554 * pointer for the second address argument even
1557 conversation = find_conversation(pinfo->fd->num, &null_address,
1558 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1559 pinfo->destport, 0);
1561 if (conversation != NULL)
1563 /* Look only for matching request, if
1564 matching conversation is available. */
1565 mgcp_call_key.transid = mi->transid;
1566 mgcp_call_key.conversation = conversation;
1567 mgcp_call = g_hash_table_lookup(mgcp_calls, &mgcp_call_key);
1570 /* Indicate the frame to which this is a reply. */
1571 if (mgcp_call->req_num)
1574 mi->request_available = TRUE;
1575 mgcp_call->responded = TRUE;
1576 mi->req_num = mgcp_call->req_num;
1577 g_strlcpy(mi->code,mgcp_call->code,5);
1578 item = proto_tree_add_uint_format(tree, hf_mgcp_req_frame,
1579 tvb, 0, 0, mgcp_call->req_num,
1580 "This is a response to a request in frame %u",
1581 mgcp_call->req_num);
1582 PROTO_ITEM_SET_GENERATED(item);
1583 nstime_delta(&delta, &pinfo->fd->abs_ts, &mgcp_call->req_time);
1584 item = proto_tree_add_time(tree, hf_mgcp_time, tvb, 0, 0, &delta);
1585 PROTO_ITEM_SET_GENERATED(item);
1588 if (mgcp_call->rsp_num == 0)
1590 /* We have not yet seen a response to that call, so
1591 this must be the first response; remember its
1593 mgcp_call->rsp_num = pinfo->fd->num;
1597 /* We have seen a response to this call - but was it
1598 *this* response? (disregard provisional responses) */
1599 if ((mgcp_call->rsp_num != pinfo->fd->num) &&
1600 (mi->rspcode >= 200) &&
1601 (mi->rspcode == mgcp_call->rspcode))
1603 /* No, so it's a duplicate response. Mark it as such. */
1604 mi->is_duplicate = TRUE;
1605 col_append_fstr(pinfo->cinfo, COL_INFO,
1606 ", Duplicate Response %u",
1611 item = proto_tree_add_uint(tree, hf_mgcp_dup, tvb, 0,0, mi->transid);
1612 PROTO_ITEM_SET_HIDDEN(item);
1613 item = proto_tree_add_uint(tree, hf_mgcp_rsp_dup,
1614 tvb, 0, 0, mi->transid);
1615 PROTO_ITEM_SET_GENERATED(item);
1616 item = proto_tree_add_uint(tree, hf_mgcp_rsp_dup_frame,
1617 tvb, 0, 0, mgcp_call->rsp_num);
1618 PROTO_ITEM_SET_GENERATED(item);
1622 /* Now store the response code (after comparison above) */
1623 mgcp_call->rspcode = mi->rspcode;
1628 hidden_item = proto_tree_add_boolean(tree, hf_mgcp_req, tvb, 0, 0, TRUE);
1629 PROTO_ITEM_SET_HIDDEN(hidden_item);
1630 /* Keep track of the address and port whence the call came,
1631 * and the port to which the call is being sent, so that
1632 * we can match up calls with replies.
1634 * If the transport is connection-oriented (we check, for
1635 * now, only for "pinfo->ptype" of PT_TCP), we take
1636 * into account the address from which the call was sent
1637 * and the address to which the call was sent, because
1638 * the addresses of the two endpoints should be the same
1639 * for all calls and replies.
1641 * If the transport is connectionless, we don't worry
1642 * about the address to which the call was sent and from
1643 * which the reply was sent, because there's no
1644 * guarantee that the reply will come from the address
1645 * to which the call was sent.
1647 if (pinfo->ptype == PT_TCP)
1649 conversation = find_conversation(pinfo->fd->num, &pinfo->src,
1650 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1651 pinfo->destport, 0);
1656 * XXX - can we just use NO_ADDR_B? Unfortunately,
1657 * you currently still have to pass a non-null
1658 * pointer for the second address argument even
1661 conversation = find_conversation(pinfo->fd->num, &pinfo->src,
1662 &null_address, pinfo->ptype, pinfo->srcport,
1663 pinfo->destport, 0);
1665 if (conversation == NULL)
1667 /* It's not part of any conversation - create a new one. */
1668 if (pinfo->ptype == PT_TCP)
1670 conversation = conversation_new(pinfo->fd->num, &pinfo->src,
1671 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1672 pinfo->destport, 0);
1676 conversation = conversation_new(pinfo->fd->num, &pinfo->src,
1677 &null_address, pinfo->ptype, pinfo->srcport,
1678 pinfo->destport, 0);
1682 /* Prepare the key data */
1683 mgcp_call_key.transid = mi->transid;
1684 mgcp_call_key.conversation = conversation;
1686 /* Look up the request */
1687 mgcp_call = g_hash_table_lookup(mgcp_calls, &mgcp_call_key);
1688 if (mgcp_call != NULL)
1690 /* We've seen a request with this TRANSID, with the same
1691 source and destination, before - but was it
1693 if (pinfo->fd->num != mgcp_call->req_num)
1695 /* No, so it's a duplicate request. Mark it as such. */
1696 mi->is_duplicate = TRUE;
1697 mi->req_num = mgcp_call->req_num;
1698 col_append_fstr(pinfo->cinfo, COL_INFO,
1699 ", Duplicate Request %u",
1704 item = proto_tree_add_uint(tree, hf_mgcp_dup, tvb, 0,0, mi->transid);
1705 PROTO_ITEM_SET_HIDDEN(item);
1706 item = proto_tree_add_uint(tree, hf_mgcp_req_dup, tvb, 0,0, mi->transid);
1707 PROTO_ITEM_SET_GENERATED(item);
1708 item = proto_tree_add_uint(tree, hf_mgcp_req_dup_frame, tvb, 0,0, mi->req_num);
1709 PROTO_ITEM_SET_GENERATED(item);
1715 /* Prepare the value data.
1716 "req_num" and "rsp_num" are frame numbers;
1717 frame numbers are 1-origin, so we use 0
1718 to mean "we don't yet know in which frame
1719 the reply for this call appears". */
1720 new_mgcp_call_key = se_alloc(sizeof(*new_mgcp_call_key));
1721 *new_mgcp_call_key = mgcp_call_key;
1722 mgcp_call = se_alloc(sizeof(*mgcp_call));
1723 mgcp_call->req_num = pinfo->fd->num;
1724 mgcp_call->rsp_num = 0;
1725 mgcp_call->transid = mi->transid;
1726 mgcp_call->responded = FALSE;
1727 mgcp_call->req_time=pinfo->fd->abs_ts;
1728 g_strlcpy(mgcp_call->code,mi->code,5);
1731 g_hash_table_insert(mgcp_calls, new_mgcp_call_key, mgcp_call);
1733 if (mgcp_call->rsp_num)
1735 proto_item* item = proto_tree_add_uint_format(tree, hf_mgcp_rsp_frame,
1736 tvb, 0, 0, mgcp_call->rsp_num,
1737 "The response to this request is in frame %u",
1738 mgcp_call->rsp_num);
1739 PROTO_ITEM_SET_GENERATED(item);
1746 mi->mgcp_type = mgcp_type;
1749 mi->req_time.secs=mgcp_call->req_time.secs;
1750 mi->req_time.nsecs=mgcp_call->req_time.nsecs;
1754 tap_queue_packet(mgcp_tap, pinfo, mi);
1758 * dissect_mgcp_params - Dissects the parameters of an MGCP message.
1759 * Adds the appropriate headers fields to
1760 * tree for the dissection of the parameters
1761 * of an MGCP message.
1764 * tvb - The tvb containing the parameters of an MGCP message. This
1765 * tvb is presumed to ONLY contain the part of the MGCP
1766 * message which contains the MGCP parameters.
1767 * tree - The tree from which to hang the structured information parsed
1768 * from the parameters of the MGCP message.
1770 static void dissect_mgcp_params(tvbuff_t *tvb, proto_tree *tree)
1772 int linelen, tokenlen, *my_param;
1773 gint tvb_lineend, tvb_linebegin, tvb_len, old_lineend;
1774 gint tvb_tokenbegin;
1775 proto_tree *mgcp_param_ti, *mgcp_param_tree;
1777 tvb_len = tvb_length(tvb);
1779 tvb_lineend = tvb_linebegin;
1783 mgcp_param_ti = proto_tree_add_item(tree, hf_mgcp_params, tvb,
1784 tvb_linebegin, tvb_len, ENC_NA);
1785 proto_item_set_text(mgcp_param_ti, "Parameters");
1786 mgcp_param_tree = proto_item_add_subtree(mgcp_param_ti, ett_mgcp_param);
1788 /* Parse the parameters */
1789 while (tvb_lineend < tvb_len)
1791 old_lineend = tvb_lineend;
1792 linelen = tvb_find_line_end(tvb, tvb_linebegin, -1,&tvb_lineend,FALSE);
1793 tvb_tokenbegin = tvb_parse_param(tvb, tvb_linebegin, linelen, &my_param);
1797 if (*my_param == hf_mgcp_param_connectionparam)
1799 tokenlen = tvb_find_line_end(tvb,tvb_tokenbegin,-1,&tvb_lineend,FALSE);
1800 dissect_mgcp_connectionparams(mgcp_param_tree, tvb, tvb_linebegin,
1801 tvb_tokenbegin - tvb_linebegin, tokenlen);
1804 if (*my_param == hf_mgcp_param_localconnoptions)
1806 tokenlen = tvb_find_line_end(tvb,tvb_tokenbegin,-1,&tvb_lineend,FALSE);
1807 dissect_mgcp_localconnectionoptions(mgcp_param_tree, tvb, tvb_linebegin,
1808 tvb_tokenbegin - tvb_linebegin, tokenlen);
1812 tokenlen = tvb_find_line_end(tvb,tvb_tokenbegin,-1,&tvb_lineend,FALSE);
1813 proto_tree_add_string(mgcp_param_tree,*my_param, tvb,
1814 tvb_linebegin, linelen,
1815 tvb_format_text(tvb,tvb_tokenbegin, tokenlen));
1819 tvb_linebegin = tvb_lineend;
1820 /* Its a infinite loop if we didn't advance (or went backwards) */
1821 if (old_lineend >= tvb_lineend)
1823 THROW(ReportedBoundsError);
1829 /* Dissect the connection params */
1831 dissect_mgcp_connectionparams(proto_tree *parent_tree, tvbuff_t *tvb, gint offset, gint param_type_len, gint param_val_len)
1833 proto_tree *tree = parent_tree;
1834 proto_item *item = NULL;
1836 gchar *tokenline = NULL;
1837 gchar **tokens = NULL;
1838 gchar **typval = NULL;
1846 item = proto_tree_add_item(parent_tree, hf_mgcp_param_connectionparam, tvb, offset, param_type_len+param_val_len, ENC_ASCII|ENC_NA);
1847 tree = proto_item_add_subtree(item, ett_mgcp_param_connectionparam);
1851 offset += param_type_len; /* skip the P: */
1852 tokenline = tvb_get_ephemeral_string(tvb, offset, param_val_len);
1854 /* Split into type=value pairs separated by comma */
1855 tokens = ep_strsplit(tokenline, ",", -1);
1857 for (i = 0; tokens[i] != NULL; i++)
1859 tokenlen = (int)strlen(tokens[i]);
1860 typval = ep_strsplit(tokens[i], "=", 2);
1861 if ((typval[0] != NULL) && (typval[1] != NULL))
1863 if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PS"))
1865 hf_uint = hf_mgcp_param_connectionparam_ps;
1867 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "OS"))
1869 hf_uint = hf_mgcp_param_connectionparam_os;
1871 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PR"))
1873 hf_uint = hf_mgcp_param_connectionparam_pr;
1875 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "OR"))
1877 hf_uint = hf_mgcp_param_connectionparam_or;
1879 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PL"))
1881 hf_uint = hf_mgcp_param_connectionparam_pl;
1883 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "JI"))
1885 hf_uint = hf_mgcp_param_connectionparam_ji;
1887 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "LA"))
1889 hf_uint = hf_mgcp_param_connectionparam_la;
1891 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PC/RPS"))
1893 hf_uint = hf_mgcp_param_connectionparam_pcrps;
1894 } else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PC/ROS"))
1896 hf_uint = hf_mgcp_param_connectionparam_pcros;
1898 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PC/RPL"))
1900 hf_uint = hf_mgcp_param_connectionparam_pcrpl;
1902 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PC/RJI"))
1904 hf_uint = hf_mgcp_param_connectionparam_pcrji;
1906 else if (!g_ascii_strncasecmp(g_strstrip(typval[0]), "X-", 2))
1908 hf_string = hf_mgcp_param_connectionparam_x;
1920 proto_tree_add_uint(tree, hf_uint, tvb, offset, tokenlen, atol(typval[1]));
1922 else if (hf_string != -1)
1924 proto_tree_add_string(tree, hf_string, tvb, offset, tokenlen, g_strstrip(typval[1]));
1928 proto_tree_add_text(tree, tvb, offset, tokenlen, "Unknown parameter: %s", tokens[i]);
1934 proto_tree_add_text(tree, tvb, offset, tokenlen, "Malformed parameter: %s", tokens[i]);
1936 offset += tokenlen + 1; /* 1 extra for the delimiter */
1941 /* Dissect the local connection option */
1943 dissect_mgcp_localconnectionoptions(proto_tree *parent_tree, tvbuff_t *tvb, gint offset, gint param_type_len, gint param_val_len)
1945 proto_tree *tree = parent_tree;
1946 proto_item *item = NULL;
1948 gchar *tokenline = NULL;
1949 gchar **tokens = NULL;
1950 gchar **typval = NULL;
1958 item = proto_tree_add_item(parent_tree, hf_mgcp_param_localconnoptions, tvb, offset, param_type_len+param_val_len, ENC_ASCII|ENC_NA);
1959 tree = proto_item_add_subtree(item, ett_mgcp_param_localconnectionoptions);
1963 offset += param_type_len; /* skip the L: */
1964 tokenline = tvb_get_ephemeral_string(tvb, offset, param_val_len);
1966 /* Split into type=value pairs separated by comma */
1967 tokens = ep_strsplit(tokenline, ",", -1);
1968 for (i = 0; tokens[i] != NULL; i++)
1973 tokenlen = (int)strlen(tokens[i]);
1974 typval = ep_strsplit(tokens[i], ":", 2);
1975 if ((typval[0] != NULL) && (typval[1] != NULL))
1977 if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "p"))
1979 hf_uint = hf_mgcp_param_localconnoptions_p;
1981 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "a"))
1983 hf_string = hf_mgcp_param_localconnoptions_a;
1985 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "s"))
1987 hf_string = hf_mgcp_param_localconnoptions_s;
1989 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "e"))
1991 hf_string = hf_mgcp_param_localconnoptions_e;
1993 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "sc-rtp"))
1995 hf_string = hf_mgcp_param_localconnoptions_scrtp;
1997 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "sc-rtcp"))
1999 hf_string = hf_mgcp_param_localconnoptions_scrtcp;
2001 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "b"))
2003 hf_string = hf_mgcp_param_localconnoptions_b;
2005 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "es-ccd"))
2007 hf_string = hf_mgcp_param_localconnoptions_esccd;
2009 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "es-cci"))
2011 hf_string = hf_mgcp_param_localconnoptions_escci;
2013 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "dq-gi"))
2015 hf_string = hf_mgcp_param_localconnoptions_dqgi;
2017 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "dq-rd"))
2019 hf_string = hf_mgcp_param_localconnoptions_dqrd;
2021 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "dq-ri"))
2023 hf_string = hf_mgcp_param_localconnoptions_dqri;
2025 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "dq-rr"))
2027 hf_string = hf_mgcp_param_localconnoptions_dqrr;
2029 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "k"))
2031 hf_string = hf_mgcp_param_localconnoptions_k;
2033 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "gc"))
2035 hf_uint = hf_mgcp_param_localconnoptions_gc;
2037 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "fmtp"))
2039 hf_string = hf_mgcp_param_localconnoptions_fmtp;
2041 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "nt"))
2043 hf_string = hf_mgcp_param_localconnoptions_nt;
2045 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "o-fmtp"))
2047 hf_string = hf_mgcp_param_localconnoptions_ofmtp;
2049 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "r"))
2051 hf_string = hf_mgcp_param_localconnoptions_r;
2053 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "t"))
2055 hf_string = hf_mgcp_param_localconnoptions_t;
2057 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "r-cnf"))
2059 hf_string = hf_mgcp_param_localconnoptions_rcnf;
2061 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "r-dir"))
2063 hf_string = hf_mgcp_param_localconnoptions_rdir;
2065 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "r-sh"))
2067 hf_string = hf_mgcp_param_localconnoptions_rsh;
2080 proto_tree_add_uint(tree, hf_uint, tvb, offset, tokenlen, atol(typval[1]));
2082 else if (hf_string != -1)
2084 proto_tree_add_string(tree, hf_string, tvb, offset, tokenlen, g_strstrip(typval[1]));
2088 proto_tree_add_text(tree, tvb, offset, tokenlen, "Unknown parameter: %s", tokens[i]);
2094 proto_tree_add_text(tree, tvb, offset, tokenlen, "Malformed parameter: %s", tokens[i]);
2096 offset += tokenlen + 1; /* 1 extra for the delimiter */
2103 * tvb_find_null_line - Returns the length from offset to the first null
2104 * line found (a null line is a line that begins
2105 * with a CR or LF. The offset to the first character
2106 * after the null line is written into the gint pointed
2107 * to by next_offset.
2110 * tvb - The tvbuff in which we are looking for a null line.
2111 * offset - The offset in tvb at which we will begin looking for
2113 * len - The maximum distance from offset in tvb that we will look for
2114 * a null line. If it is -1 we will look to the end of the buffer.
2116 * next_offset - The location to write the offset of first character
2117 * FOLLOWING the null line.
2119 * Returns: The length from offset to the first character BEFORE
2122 static gint tvb_find_null_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset)
2124 gint tvb_lineend,tvb_current_len,tvb_linebegin,maxoffset;
2127 tvb_linebegin = offset;
2128 tvb_lineend = tvb_linebegin;
2130 /* Simple setup to allow for the traditional -1 search to the end of the tvbuff */
2133 tvb_current_len = len;
2137 tvb_current_len = tvb_length_remaining(tvb,offset);
2140 maxoffset = (tvb_current_len - 1) + offset;
2142 /* Loop around until we either find a line begining with a carriage return
2143 or newline character or until we hit the end of the tvbuff. */
2146 tvb_linebegin = tvb_lineend;
2147 tvb_current_len = tvb_length_remaining(tvb,tvb_linebegin);
2148 tvb_find_line_end(tvb, tvb_linebegin, tvb_current_len, &tvb_lineend,FALSE);
2149 tempchar = tvb_get_guint8(tvb,tvb_linebegin);
2150 } while (tempchar != '\r' && tempchar != '\n' && tvb_lineend <= maxoffset);
2153 *next_offset = tvb_lineend;
2155 if (tvb_lineend <= maxoffset)
2157 tvb_current_len = tvb_linebegin - offset;
2161 tvb_current_len = tvb_length_remaining(tvb,offset);
2164 return tvb_current_len;
2168 * tvb_find_dot_line - Returns the length from offset to the first line
2169 * containing only a dot (.) character. A line
2170 * containing only a dot is used to indicate a
2171 * separation between multiple MGCP messages
2172 * piggybacked in the same UDP packet.
2175 * tvb - The tvbuff in which we are looking for a dot line.
2176 * offset - The offset in tvb at which we will begin looking for
2178 * len - The maximum distance from offset in tvb that we will look for
2179 * a dot line. If it is -1 we will look to the end of the buffer.
2181 * next_offset - The location to write the offset of first character
2182 * FOLLOWING the dot line.
2184 * Returns: The length from offset to the first character BEFORE
2185 * the dot line or -1 if the character at offset is a .
2186 * followed by a newline or a carriage return.
2188 static gint tvb_find_dot_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset)
2190 gint tvb_current_offset, tvb_current_len, maxoffset,tvb_len;
2192 tvb_current_offset = offset;
2193 tvb_current_len = len;
2194 tvb_len = tvb_length(tvb);
2198 maxoffset = tvb_len - 1;
2202 maxoffset = (len - 1) + offset;
2204 tvb_current_offset = offset -1;
2208 tvb_current_offset = tvb_find_guint8(tvb, tvb_current_offset+1,
2209 tvb_current_len, '.');
2210 tvb_current_len = maxoffset - tvb_current_offset + 1;
2212 /* If we didn't find a . then break out of the loop */
2213 if (tvb_current_offset == -1)
2218 /* Do we have and characters following the . ? */
2219 if (tvb_current_offset < maxoffset)
2221 tempchar = tvb_get_guint8(tvb,tvb_current_offset+1);
2222 /* Are the characters that follow the dot a newline or carriage return ? */
2223 if (tempchar == '\r' || tempchar == '\n')
2225 /* Do we have any charaters that proceed the . ? */
2226 if (tvb_current_offset == 0)
2232 tempchar = tvb_get_guint8(tvb,tvb_current_offset-1);
2234 /* Are the characters that follow the dot a newline or a
2235 carriage return ? */
2236 if (tempchar == '\r' || tempchar == '\n')
2244 if (tvb_current_offset == maxoffset)
2246 if (tvb_current_offset == 0)
2252 tempchar = tvb_get_guint8(tvb,tvb_current_offset-1);
2253 if (tempchar == '\r' || tempchar == '\n')
2259 } while (tvb_current_offset < maxoffset);
2263 * So now we either have the tvb_current_offset of a . in a dot line
2264 * or a tvb_current_offset of -1
2266 if (tvb_current_offset == -1)
2268 tvb_current_offset = maxoffset +1;
2269 *next_offset = maxoffset + 1;
2273 tvb_find_line_end(tvb,tvb_current_offset,tvb_current_len,next_offset,FALSE);
2276 if (tvb_current_offset == offset)
2278 tvb_current_len = -1;
2282 tvb_current_len = tvb_current_offset - offset;
2285 return tvb_current_len;