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 * NCS 1.5: PKT-SP-NCS1.5-I03-070412, April 12, 2007 Cable Television
11 * Laboratories, Inc., http://www.PacketCable.com/
12 * www.iana.org/assignments/mgcp-localconnectionoptions
16 * Copyright (c) 2000 by Ed Warnicke <hagbard@physics.rutgers.edu>
17 * Copyright (c) 2004 by Thomas Anders <thomas.anders [AT] blue-cable.de>
19 * Wireshark - Network traffic analyzer
20 * By Gerald Combs <gerald@wireshark.org>
21 * Copyright 1999 Gerald Combs
23 * This program is free software; you can redistribute it and/or
24 * modify it under the terms of the GNU General Public License
25 * as published by the Free Software Foundation; either version 2
26 * of the License, or (at your option) any later version.
28 * This program is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU General Public License for more details.
33 * You should have received a copy of the GNU General Public License
34 * along with this program; if not, write to the Free Software
35 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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_localconnoptions_mp = -1;
107 static int hf_mgcp_param_localconnoptions_fxr = -1;
108 static int hf_mgcp_param_connectionmode = -1;
109 static int hf_mgcp_param_reqevents = -1;
110 static int hf_mgcp_param_restartmethod = -1;
111 static int hf_mgcp_param_restartdelay = -1;
112 static int hf_mgcp_param_signalreq = -1;
113 static int hf_mgcp_param_digitmap = -1;
114 static int hf_mgcp_param_observedevent = -1;
115 static int hf_mgcp_param_connectionparam = -1;
116 static int hf_mgcp_param_connectionparam_ps = -1;
117 static int hf_mgcp_param_connectionparam_os = -1;
118 static int hf_mgcp_param_connectionparam_pr = -1;
119 static int hf_mgcp_param_connectionparam_or = -1;
120 static int hf_mgcp_param_connectionparam_pl = -1;
121 static int hf_mgcp_param_connectionparam_ji = -1;
122 static int hf_mgcp_param_connectionparam_la = -1;
123 static int hf_mgcp_param_connectionparam_pcrps = -1;
124 static int hf_mgcp_param_connectionparam_pcros = -1;
125 static int hf_mgcp_param_connectionparam_pcrpl = -1;
126 static int hf_mgcp_param_connectionparam_pcrji = -1;
127 static int hf_mgcp_param_connectionparam_x = -1;
128 static int hf_mgcp_param_reasoncode = -1;
129 static int hf_mgcp_param_eventstates = -1;
130 static int hf_mgcp_param_specificendpoint = -1;
131 static int hf_mgcp_param_secondendpointid = -1;
132 static int hf_mgcp_param_reqinfo = -1;
133 static int hf_mgcp_param_quarantinehandling = -1;
134 static int hf_mgcp_param_detectedevents = -1;
135 static int hf_mgcp_param_capabilities = -1;
136 static int hf_mgcp_param_maxmgcpdatagram = -1;
137 static int hf_mgcp_param_packagelist = -1;
138 static int hf_mgcp_param_extension = -1;
139 static int hf_mgcp_param_extension_critical = -1;
140 static int hf_mgcp_param_invalid = -1;
141 static int hf_mgcp_messagecount = -1;
142 static int hf_mgcp_dup = -1;
143 static int hf_mgcp_req_dup = -1;
144 static int hf_mgcp_req_dup_frame = -1;
145 static int hf_mgcp_rsp_dup = -1;
146 static int hf_mgcp_rsp_dup_frame = -1;
148 static const value_string mgcp_return_code_vals[] = {
149 {000, "Response Acknowledgement"},
150 {100, "The transaction is currently being executed. An actual completion message will follow on later."},
151 {101, "The transaction has been queued for execution. An actual completion message will follow later."},
152 {200, "The requested transaction was executed normally."},
153 {250, "The connection was deleted."},
154 {400, "The transaction could not be executed, due to a transient error."},
155 {401, "The phone is already off hook"},
156 {402, "The phone is already on hook"},
157 {403, "The transaction could not be executed, because the endpoint does not have sufficient resources at this time"},
158 {404, "Insufficient bandwidth at this time"},
159 {405, "The transaction could not be executed, because the endpoint is \"restarting\"."},
160 {406, "Transaction time-out. The transaction did not complete in a reasonable period of time and has been aborted."},
161 {407, "Transaction aborted. The transaction was aborted by some external action, e.g., a ModifyConnection command aborted by a DeleteConnection command."},
162 {409, "The transaction could not be executed because of internal overload."},
163 {410, "No endpoint available. A valid \"any of\" wildcard was used, however there was no endpoint available to satisfy the request."},
164 {500, "The transaction could not be executed, because the endpoint is unknown."},
165 {501, "The transaction could not be executed, because the endpoint is not ready."},
166 {502, "The transaction could not be executed, because the endpoint does not have sufficient resources"},
167 {503, "\"All of\" wildcard too complicated."},
168 {504, "Unknown or unsupported command."},
169 {505, "Unsupported RemoteConnectionDescriptor."},
170 {506, "Unable to satisfy both LocalConnectionOptions and RemoteConnectionDescriptor."},
171 {507, "Unsupported functionality."},
172 {508, "Unknown or unsupported quarantine handling."},
173 {509, "Error in RemoteConnectionDescriptor."},
174 {510, "The transaction could not be executed, because a protocol error was detected."},
175 {511, "The transaction could not be executed, because the command contained an unrecognized extension."},
176 {512, "The transaction could not be executed, because the gateway is not equipped to detect one of the requested events."},
177 {513, "The transaction could not be executed, because the gateway is not equipped to generate one of the requested signals."},
178 {514, "The transaction could not be executed, because the gateway cannot send the specified announcement."},
179 {515, "The transaction refers to an incorrect connection-id (may have been already deleted)"},
180 {516, "The transaction refers to an unknown call-id."},
181 {517, "Unsupported or invalid mode."},
182 {518, "Unsupported or unknown package."},
183 {519, "Endpoint does not have a digit map."},
184 {520, "The transaction could not be executed, because the endpoint is 'restarting'."},
185 {521, "Endpoint redirected to another Call Agent."},
186 {522, "No such event or signal."},
187 {523, "Unknown action or illegal combination of actions"},
188 {524, "Internal inconsistency in LocalConnectionOptions"},
189 {525, "Unknown extension in LocalConnectionOptions"},
190 {526, "Insufficient bandwidth"},
191 {527, "Missing RemoteConnectionDescriptor"},
192 {528, "Incompatible protocol version"},
193 {529, "Internal hardware failure"},
194 {530, "CAS signaling protocol error."},
195 {531, "failure of a grouping of trunks (e.g. facility failure)."},
196 {532, "Unsupported value(s) in LocalConnectionOptions."},
197 {533, "Response too large."},
198 {534, "Codec negotiation failure."},
199 {535, "Packetization period not supported"},
200 {536, "Unknown or unsupported RestartMethod"},
201 {537, "Unknown or unsupported digit map extension"},
202 {538, "Event/signal parameter error (e.g., missing, erroneous, unsupported, unknown, etc.)"},
203 {539, "Invalid or unsupported command parameter."},
204 {540, "Per endpoint connection limit exceeded."},
205 {541, "Invalid or unsupported LocalConnectionOptions"},
209 /* TODO: add/use when tested/have capture to test with */
211 static const value_string mgcp_reason_code_vals[] = {
212 {0, "Endpoint state is normal"},
213 {900, "Endpoint malfunctioning."},
214 {901, "Endpoint taken out-of-service."},
215 {902, "Loss of lower layer connectivity (e.g., downstream sync)."},
216 {903, "QoS resource reservation was lost."},
217 {904, "Manual intervention."},
218 {905, "Facility failure (e.g., DS-0 failure)."},
225 * Define the trees for mgcp
226 * We need one for MGCP itself, one for the MGCP paramters and one
227 * for each of the dissected parameters
229 static int ett_mgcp = -1;
230 static int ett_mgcp_param = -1;
231 static int ett_mgcp_param_connectionparam = -1;
232 static int ett_mgcp_param_localconnectionoptions = -1;
235 * Define the tap for mgcp
237 static int mgcp_tap = -1;
240 * Here are the global variables associated with
241 * the various user definable characteristics of the dissection
243 * MGCP has two kinds of "agents", gateways and callagents. Callagents
244 * control gateways in a master/slave sort of arrangement. Since gateways
245 * and callagents have different well known ports and could both
246 * operate under either udp or tcp we have rather a lot of port info to
249 * global_mgcp_raw_text determines whether we are going to display
250 * the raw text of the mgcp message, much like the HTTP dissector does.
253 static guint global_mgcp_gateway_tcp_port = TCP_PORT_MGCP_GATEWAY;
254 static guint global_mgcp_gateway_udp_port = UDP_PORT_MGCP_GATEWAY;
255 static guint global_mgcp_callagent_tcp_port = TCP_PORT_MGCP_CALLAGENT;
256 static guint global_mgcp_callagent_udp_port = UDP_PORT_MGCP_CALLAGENT;
257 static gboolean global_mgcp_raw_text = FALSE;
258 static gboolean global_mgcp_message_count = FALSE;
260 /* Some basic utility functions that are specific to this dissector */
261 static gboolean is_mgcp_verb(tvbuff_t *tvb, gint offset, gint maxlength, const gchar **verb_name);
262 static gboolean is_mgcp_rspcode(tvbuff_t *tvb, gint offset, gint maxlength);
263 static gint tvb_parse_param(tvbuff_t *tvb, gint offset, gint maxlength, int** hf);
266 * The various functions that either dissect some
267 * subpart of MGCP. These aren't really proto dissectors but they
268 * are written in the same style.
270 static void dissect_mgcp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
271 proto_tree *mgcp_tree, proto_tree *ti);
272 static void dissect_mgcp_firstline(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
273 static void dissect_mgcp_params(tvbuff_t *tvb, proto_tree *tree);
274 static void dissect_mgcp_connectionparams(proto_tree *parent_tree, tvbuff_t *tvb,
275 gint offset, gint param_type_len,
277 static void dissect_mgcp_localconnectionoptions(proto_tree *parent_tree, tvbuff_t *tvb,
278 gint offset, gint param_type_len,
282 static void mgcp_raw_text_add(tvbuff_t *tvb, proto_tree *tree);
285 * Some functions which should be moved to a library
286 * as I think that people may find them of general usefulness.
288 static gint tvb_find_null_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset);
289 static gint tvb_find_dot_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset);
290 static gboolean is_rfc2234_alpha(guint8 c);
292 static dissector_handle_t sdp_handle;
293 static dissector_handle_t mgcp_handle;
295 dissect_asciitpkt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
296 dissector_handle_t subdissector_handle);
297 extern guint16 is_asciitpkt(tvbuff_t *tvb);
300 * Init Hash table stuff
303 typedef struct _mgcp_call_info_key
306 conversation_t *conversation;
307 } mgcp_call_info_key;
309 static GHashTable *mgcp_calls;
312 static gint mgcp_call_equal(gconstpointer k1, gconstpointer k2)
314 const mgcp_call_info_key* key1 = (const mgcp_call_info_key*) k1;
315 const mgcp_call_info_key* key2 = (const mgcp_call_info_key*) k2;
317 return (key1->transid == key2->transid &&
318 key1->conversation == key2->conversation);
321 /* Calculate a hash key */
322 static guint mgcp_call_hash(gconstpointer k)
324 const mgcp_call_info_key* key = (const mgcp_call_info_key*) k;
326 return key->transid + key->conversation->index;
330 /************************************************************************
331 * dissect_mgcp - The dissector for the Media Gateway Control Protocol
332 ************************************************************************/
333 static int dissect_mgcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
336 guint32 num_messages;
337 gint tvb_sectionend,tvb_sectionbegin, tvb_len;
338 proto_tree *mgcp_tree, *ti;
339 const gchar *verb_name = "";
341 /* Initialize variables */
343 tvb_sectionbegin = tvb_sectionend;
345 tvb_len = tvb_length(tvb);
351 * Check to see whether we're really dealing with MGCP by looking
352 * for a valid MGCP verb or response code. This isn't infallible,
353 * but it's cheap and it's better than nothing.
355 if (is_mgcp_verb(tvb,0,tvb_len, &verb_name) || is_mgcp_rspcode(tvb,0,tvb_len))
358 * Set the columns now, so that they'll be set correctly if we throw
359 * an exception. We can set them later as well....
361 col_set_str(pinfo->cinfo, COL_PROTOCOL, "MGCP");
362 col_clear(pinfo->cinfo, COL_INFO);
365 * Loop through however many mgcp messages may be stuck in
366 * this packet using piggybacking
373 /* Create our mgcp subtree */
374 ti = proto_tree_add_item(tree,proto_mgcp,tvb,0,0, ENC_NA);
375 mgcp_tree = proto_item_add_subtree(ti, ett_mgcp);
378 sectionlen = tvb_find_dot_line(tvb, tvb_sectionbegin, -1, &tvb_sectionend);
379 if (sectionlen != -1)
381 dissect_mgcp_message(tvb_new_subset(tvb, tvb_sectionbegin,
383 pinfo, tree, mgcp_tree,ti);
384 tvb_sectionbegin = tvb_sectionend;
390 } while (tvb_sectionend < tvb_len);
394 proto_item *tii = proto_tree_add_uint(mgcp_tree, hf_mgcp_messagecount, tvb,
395 0 ,0 , num_messages);
396 PROTO_ITEM_SET_HIDDEN(tii);
400 * Add our column information after dissecting SDP
401 * in order to prevent the column info changing to reflect the SDP
402 * (when showing message count)
404 tvb_sectionbegin = 0;
405 if (global_mgcp_message_count == TRUE )
407 if (num_messages > 1)
409 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "MGCP (%i messages)",num_messages);
413 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "MGCP (%i message)",num_messages);
417 sectionlen = tvb_find_line_end(tvb, tvb_sectionbegin,-1,
418 &tvb_sectionend,FALSE);
419 col_prepend_fstr(pinfo->cinfo, COL_INFO, "%s",
420 tvb_format_text(tvb, tvb_sectionbegin, sectionlen));
427 /************************************************************************
428 * dissect_tpkt_mgcp - The dissector for the ASCII TPKT Media Gateway Control Protocol
429 ************************************************************************/
430 static int dissect_tpkt_mgcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
435 /* Check whether this looks like a ASCII TPKT-encapsulated
438 ascii_tpkt = is_asciitpkt(tvb);
440 if (ascii_tpkt != 1 )
443 * It's not a ASCII TPKT packet
446 offset = dissect_mgcp(tvb, pinfo, tree, NULL);
451 * Dissect ASCII TPKT header
453 dissect_asciitpkt(tvb, pinfo, tree, mgcp_handle);
454 offset = tvb_length(tvb);
460 #define MAX_MGCP_MESSAGES_IN_PACKET 5
461 static mgcp_info_t pi_arr[MAX_MGCP_MESSAGES_IN_PACKET];
462 static int pi_current = 0;
463 static mgcp_info_t *mi;
465 /* Dissect an individual MGCP message */
466 static void dissect_mgcp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
467 proto_tree *mgcp_tree, proto_tree *ti)
469 /* Declare variables */
471 gint tvb_sectionend,tvb_sectionbegin, tvb_len;
473 const gchar *verb_name = "";
475 /* Initialise stat info for passing to tap */
477 if (pi_current == MAX_MGCP_MESSAGES_IN_PACKET)
479 /* Overwrite info in first struct if run out of space... */
482 mi = &pi_arr[pi_current];
485 mi->mgcp_type = MGCP_OTHERS;
488 mi->req_time.secs = 0;
489 mi->req_time.nsecs = 0;
490 mi->is_duplicate = FALSE;
491 mi->request_available = FALSE;
493 mi->endpointId = NULL;
494 mi->observedEvents = NULL;
496 mi->signalReq = NULL;
497 mi->hasDigitMap = FALSE;
499 /* Initialize variables */
501 tvb_sectionbegin = tvb_sectionend;
503 tvb_len = tvb_length(tvb);
506 * Check to see whether we're really dealing with MGCP by looking
507 * for a valid MGCP verb or response code. This isn't infallible,
508 * but it's cheap and it's better than nothing.
510 if (is_mgcp_verb(tvb,0,tvb_len,&verb_name) || is_mgcp_rspcode(tvb,0,tvb_len))
512 /* dissect first line */
513 tvb_sectionbegin = 0;
514 tvb_sectionend = tvb_sectionbegin;
515 sectionlen = tvb_find_line_end(tvb,0,-1,&tvb_sectionend,FALSE);
518 dissect_mgcp_firstline(tvb_new_subset(tvb, tvb_sectionbegin,
519 sectionlen,-1), pinfo,
522 tvb_sectionbegin = tvb_sectionend;
525 if (tvb_sectionbegin < tvb_len)
527 sectionlen = tvb_find_null_line(tvb, tvb_sectionbegin, -1,
531 dissect_mgcp_params(tvb_new_subset(tvb, tvb_sectionbegin, sectionlen, -1),
533 tvb_sectionbegin = tvb_sectionend;
537 /* Set the mgcp payload length correctly so we don't include any
539 sectionlen = tvb_sectionend;
540 proto_item_set_len(ti,sectionlen);
542 /* Display the raw text of the mgcp message if desired */
544 /* Do we want to display the raw text of our MGCP packet? */
545 if (global_mgcp_raw_text)
548 mgcp_raw_text_add(tvb, mgcp_tree);
551 /* Dissect sdp payload */
552 if (tvb_sectionend < tvb_len)
554 next_tvb = tvb_new_subset_remaining(tvb, tvb_sectionend);
555 call_dissector(sdp_handle, next_tvb, pinfo, tree);
562 * Add the raw text of the message to the dissect tree if appropriate
563 * preferences are specified.
565 static void mgcp_raw_text_add(tvbuff_t *tvb, proto_tree *tree)
567 gint tvb_linebegin,tvb_lineend,tvb_len,linelen;
570 tvb_len = tvb_length(tvb);
574 tvb_find_line_end(tvb,tvb_linebegin,-1,&tvb_lineend,FALSE);
575 linelen = tvb_lineend - tvb_linebegin;
576 proto_tree_add_text(tree, tvb, tvb_linebegin, linelen, "%s",
577 tvb_format_text(tvb, tvb_linebegin, linelen));
578 tvb_linebegin = tvb_lineend;
579 } while (tvb_lineend < tvb_len);
582 /* Discard and init any state we've saved */
583 static void mgcp_init_protocol(void)
585 if (mgcp_calls != NULL)
587 g_hash_table_destroy(mgcp_calls);
591 mgcp_calls = g_hash_table_new(mgcp_call_hash, mgcp_call_equal);
594 /* Register all the bits needed with the filtering engine */
595 void proto_register_mgcp(void)
597 static hf_register_info hf[] =
600 { "Request", "mgcp.req", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
601 "True if MGCP request", HFILL }},
603 { "Response", "mgcp.rsp", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
604 "TRUE if MGCP response", HFILL }},
605 { &hf_mgcp_req_frame,
606 { "Request Frame", "mgcp.reqframe", FT_FRAMENUM, BASE_NONE, NULL, 0,
608 { &hf_mgcp_rsp_frame,
609 { "Response Frame", "mgcp.rspframe", FT_FRAMENUM, BASE_NONE, NULL, 0,
612 { "Time from request", "mgcp.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0,
613 "Timedelta between Request and Response", HFILL }},
615 { "Verb", "mgcp.req.verb", FT_STRING, BASE_NONE, NULL, 0x0,
616 "Name of the verb", HFILL }},
617 { &hf_mgcp_req_endpoint,
618 { "Endpoint", "mgcp.req.endpoint", FT_STRING, BASE_NONE, NULL, 0x0,
619 "Endpoint referenced by the message", HFILL }},
621 { "Transaction ID", "mgcp.transid", FT_STRING, BASE_NONE, NULL, 0x0,
622 "Transaction ID of this message", HFILL }},
624 { "Version", "mgcp.version", FT_STRING, BASE_NONE, NULL, 0x0,
625 "MGCP Version", HFILL }},
626 { &hf_mgcp_rsp_rspcode,
627 { "Response Code", "mgcp.rsp.rspcode", FT_UINT32, BASE_DEC, VALS(mgcp_return_code_vals), 0x0,
629 { &hf_mgcp_rsp_rspstring,
630 { "Response String", "mgcp.rsp.rspstring", FT_STRING, BASE_NONE, NULL, 0x0,
633 { "Parameters", "mgcp.params", FT_NONE, BASE_NONE, NULL, 0x0,
634 "MGCP parameters", HFILL }},
635 { &hf_mgcp_param_rspack,
636 { "ResponseAck (K)", "mgcp.param.rspack", FT_STRING, BASE_NONE, NULL, 0x0,
637 "Response Ack", HFILL }},
638 { &hf_mgcp_param_bearerinfo,
639 { "BearerInformation (B)", "mgcp.param.bearerinfo", FT_STRING, BASE_NONE, NULL, 0x0,
640 "Bearer Information", HFILL }},
641 { &hf_mgcp_param_callid,
642 { "CallId (C)", "mgcp.param.callid", FT_STRING, BASE_NONE, NULL, 0x0,
644 { &hf_mgcp_param_connectionid,
645 {"ConnectionIdentifier (I)", "mgcp.param.connectionid", FT_STRING, BASE_NONE, NULL, 0x0,
646 "Connection Identifier", HFILL }},
647 { &hf_mgcp_param_secondconnectionid,
648 { "SecondConnectionID (I2)", "mgcp.param.secondconnectionid", FT_STRING, BASE_NONE, NULL, 0x0,
649 "Second Connection Identifier", HFILL }},
650 { &hf_mgcp_param_notifiedentity,
651 { "NotifiedEntity (N)", "mgcp.param.notifiedentity", FT_STRING, BASE_NONE, NULL, 0x0,
652 "Notified Entity", HFILL }},
653 { &hf_mgcp_param_requestid,
654 { "RequestIdentifier (X)", "mgcp.param.requestid", FT_STRING, BASE_NONE, NULL, 0x0,
655 "Request Identifier", HFILL }},
656 { &hf_mgcp_param_localconnoptions,
657 { "LocalConnectionOptions (L)", "mgcp.param.localconnectionoptions", FT_STRING, BASE_NONE, NULL, 0x0,
658 "Local Connection Options", HFILL }},
659 { &hf_mgcp_param_localconnoptions_p,
660 { "Packetization period (p)", "mgcp.param.localconnectionoptions.p", FT_UINT32, BASE_DEC, NULL, 0x0,
661 "Packetization period", HFILL }},
662 { &hf_mgcp_param_localconnoptions_a,
663 { "Codecs (a)", "mgcp.param.localconnectionoptions.a", FT_STRING, BASE_NONE, NULL, 0x0,
665 { &hf_mgcp_param_localconnoptions_s,
666 { "Silence Suppression (s)", "mgcp.param.localconnectionoptions.s", FT_STRING, BASE_NONE, NULL, 0x0,
667 "Silence Suppression", HFILL }},
668 { &hf_mgcp_param_localconnoptions_e,
669 { "Echo Cancellation (e)", "mgcp.param.localconnectionoptions.e", FT_STRING, BASE_NONE, NULL, 0x0,
670 "Echo Cancellation", HFILL }},
671 { &hf_mgcp_param_localconnoptions_scrtp,
672 { "RTP ciphersuite (sc-rtp)", "mgcp.param.localconnectionoptions.scrtp", FT_STRING, BASE_NONE, NULL, 0x0,
673 "RTP ciphersuite", HFILL }},
674 { &hf_mgcp_param_localconnoptions_scrtcp,
675 { "RTCP ciphersuite (sc-rtcp)", "mgcp.param.localconnectionoptions.scrtcp", FT_STRING, BASE_NONE, NULL, 0x0,
676 "RTCP ciphersuite", HFILL }},
677 { &hf_mgcp_param_localconnoptions_b,
678 { "Bandwidth (b)", "mgcp.param.localconnectionoptions.b", FT_STRING, BASE_NONE, NULL, 0x0,
679 "Bandwidth", HFILL }},
680 { &hf_mgcp_param_localconnoptions_esccd,
681 { "Content Destination (es-ccd)", "mgcp.param.localconnectionoptions.esccd", FT_STRING, BASE_NONE, NULL, 0x0,
682 "Content Destination", HFILL }},
683 { &hf_mgcp_param_localconnoptions_escci,
684 { "Content Identifier (es-cci)", "mgcp.param.localconnectionoptions.escci", FT_STRING, BASE_NONE, NULL, 0x0,
685 "Content Identifier", HFILL }},
686 { &hf_mgcp_param_localconnoptions_dqgi,
687 { "D-QoS GateID (dq-gi)", "mgcp.param.localconnectionoptions.dqgi", FT_STRING, BASE_NONE, NULL, 0x0,
688 "D-QoS GateID", HFILL }},
689 { &hf_mgcp_param_localconnoptions_dqrd,
690 { "D-QoS Reserve Destination (dq-rd)", "mgcp.param.localconnectionoptions.dqrd", FT_STRING, BASE_NONE, NULL, 0x0,
691 "D-QoS Reserve Destination", HFILL }},
692 { &hf_mgcp_param_localconnoptions_dqri,
693 { "D-QoS Resource ID (dq-ri)", "mgcp.param.localconnectionoptions.dqri", FT_STRING, BASE_NONE, NULL, 0x0,
694 "D-QoS Resource ID", HFILL }},
695 { &hf_mgcp_param_localconnoptions_dqrr,
696 { "D-QoS Resource Reservation (dq-rr)", "mgcp.param.localconnectionoptions.dqrr", FT_STRING, BASE_NONE, NULL, 0x0,
697 "D-QoS Resource Reservation", HFILL }},
698 { &hf_mgcp_param_localconnoptions_k,
699 { "Encryption Key (k)", "mgcp.param.localconnectionoptions.k", FT_STRING, BASE_NONE, NULL, 0x0,
700 "Encryption Key", HFILL }},
701 { &hf_mgcp_param_localconnoptions_gc,
702 { "Gain Control (gc)", "mgcp.param.localconnectionoptions.gc", FT_UINT32, BASE_DEC, NULL, 0x0,
703 "Gain Control", HFILL }},
704 { &hf_mgcp_param_localconnoptions_fmtp,
705 { "Media Format (fmtp)", "mgcp.param.localconnectionoptions.fmtp", FT_STRING, BASE_NONE, NULL, 0x0,
706 "Media Format", HFILL }},
707 { &hf_mgcp_param_localconnoptions_nt,
708 { "Network Type (nt)", "mgcp.param.localconnectionoptions.nt", FT_STRING, BASE_NONE, NULL, 0x0,
709 "Network Type", HFILL }},
710 { &hf_mgcp_param_localconnoptions_ofmtp,
711 { "Optional Media Format (o-fmtp)", "mgcp.param.localconnectionoptions.ofmtp", FT_STRING, BASE_NONE, NULL, 0x0,
712 "Optional Media Format", HFILL }},
713 { &hf_mgcp_param_localconnoptions_r,
714 { "Resource Reservation (r)", "mgcp.param.localconnectionoptions.r", FT_STRING, BASE_NONE, NULL, 0x0,
715 "Resource Reservation", HFILL }},
716 { &hf_mgcp_param_localconnoptions_t,
717 { "Type of Service (r)", "mgcp.param.localconnectionoptions.t", FT_STRING, BASE_NONE, NULL, 0x0,
718 "Type of Service", HFILL }},
719 { &hf_mgcp_param_localconnoptions_rcnf,
720 { "Reservation Confirmation (r-cnf)", "mgcp.param.localconnectionoptions.rcnf", FT_STRING, BASE_NONE, NULL, 0x0,
721 "Reservation Confirmation", HFILL }},
722 { &hf_mgcp_param_localconnoptions_rdir,
723 { "Reservation Direction (r-dir)", "mgcp.param.localconnectionoptions.rdir", FT_STRING, BASE_NONE, NULL, 0x0,
724 "Reservation Direction", HFILL }},
725 { &hf_mgcp_param_localconnoptions_rsh,
726 { "Resource Sharing (r-sh)", "mgcp.param.localconnectionoptions.rsh", FT_STRING, BASE_NONE, NULL, 0x0,
727 "Resource Sharing", HFILL }},
728 { &hf_mgcp_param_localconnoptions_mp,
729 { "Multiple Packetization period (mp)", "mgcp.param.localconnectionoptions.mp", FT_STRING, BASE_NONE, NULL, 0x0,
730 "Multiple Packetization period", HFILL }},
731 { &hf_mgcp_param_localconnoptions_fxr,
732 { "FXR (fxr/fx)", "mgcp.param.localconnectionoptions.fxr", FT_STRING, BASE_NONE, NULL, 0x0,
734 { &hf_mgcp_param_connectionmode,
735 { "ConnectionMode (M)", "mgcp.param.connectionmode", FT_STRING, BASE_NONE, NULL, 0x0,
736 "Connection Mode", HFILL }},
737 { &hf_mgcp_param_reqevents,
738 { "RequestedEvents (R)", "mgcp.param.reqevents", FT_STRING, BASE_NONE, NULL, 0x0,
739 "Requested Events", HFILL }},
740 { &hf_mgcp_param_signalreq,
741 { "SignalRequests (S)", "mgcp.param.signalreq", FT_STRING, BASE_NONE, NULL, 0x0,
742 "Signal Request", HFILL }},
743 { &hf_mgcp_param_restartmethod,
744 { "RestartMethod (RM)", "mgcp.param.restartmethod", FT_STRING, BASE_NONE, NULL, 0x0,
745 "Restart Method", HFILL }},
746 { &hf_mgcp_param_restartdelay,
747 { "RestartDelay (RD)", "mgcp.param.restartdelay", FT_STRING, BASE_NONE, NULL, 0x0,
748 "Restart Delay", HFILL }},
749 { &hf_mgcp_param_digitmap,
750 { "DigitMap (D)", "mgcp.param.digitmap", FT_STRING, BASE_NONE, NULL, 0x0,
751 "Digit Map", HFILL }},
752 { &hf_mgcp_param_observedevent,
753 { "ObservedEvents (O)", "mgcp.param.observedevents", FT_STRING, BASE_NONE, NULL, 0x0,
754 "Observed Events", HFILL }},
755 { &hf_mgcp_param_connectionparam,
756 { "ConnectionParameters (P)", "mgcp.param.connectionparam", FT_STRING, BASE_NONE, NULL, 0x0,
757 "Connection Parameters", HFILL }},
758 { &hf_mgcp_param_connectionparam_ps,
759 { "Packets sent (PS)", "mgcp.param.connectionparam.ps", FT_UINT32, BASE_DEC, NULL, 0x0,
760 "Packets sent (P:PS)", HFILL }},
761 { &hf_mgcp_param_connectionparam_os,
762 { "Octets sent (OS)", "mgcp.param.connectionparam.os", FT_UINT32, BASE_DEC, NULL, 0x0,
763 "Octets sent (P:OS)", HFILL }},
764 { &hf_mgcp_param_connectionparam_pr,
765 { "Packets received (PR)", "mgcp.param.connectionparam.pr", FT_UINT32, BASE_DEC, NULL, 0x0,
766 "Packets received (P:PR)", HFILL }},
767 { &hf_mgcp_param_connectionparam_or,
768 { "Octets received (OR)", "mgcp.param.connectionparam.or", FT_UINT32, BASE_DEC, NULL, 0x0,
769 "Octets received (P:OR)", HFILL }},
770 { &hf_mgcp_param_connectionparam_pl,
771 { "Packets lost (PL)", "mgcp.param.connectionparam.pl", FT_UINT32, BASE_DEC, NULL, 0x0,
772 "Packets lost (P:PL)", HFILL }},
773 { &hf_mgcp_param_connectionparam_ji,
774 { "Jitter (JI)", "mgcp.param.connectionparam.ji", FT_UINT32, BASE_DEC, NULL, 0x0,
775 "Average inter-packet arrival jitter in milliseconds (P:JI)", HFILL }},
776 { &hf_mgcp_param_connectionparam_la,
777 { "Latency (LA)", "mgcp.param.connectionparam.la", FT_UINT32, BASE_DEC, NULL, 0x0,
778 "Average latency in milliseconds (P:LA)", HFILL }},
779 { &hf_mgcp_param_connectionparam_pcrps,
780 { "Remote Packets sent (PC/RPS)", "mgcp.param.connectionparam.pcrps", FT_UINT32, BASE_DEC, NULL, 0x0,
781 "Remote Packets sent (P:PC/RPS)", HFILL }},
782 { &hf_mgcp_param_connectionparam_pcros,
783 { "Remote Octets sent (PC/ROS)", "mgcp.param.connectionparam.pcros", FT_UINT32, BASE_DEC, NULL, 0x0,
784 "Remote Octets sent (P:PC/ROS)", HFILL }},
785 { &hf_mgcp_param_connectionparam_pcrpl,
786 { "Remote Packets lost (PC/RPL)", "mgcp.param.connectionparam.pcrpl", FT_UINT32, BASE_DEC, NULL, 0x0,
787 "Remote Packets lost (P:PC/RPL)", HFILL }},
788 { &hf_mgcp_param_connectionparam_pcrji,
789 { "Remote Jitter (PC/RJI)", "mgcp.param.connectionparam.pcrji", FT_UINT32, BASE_DEC, NULL, 0x0,
790 "Remote Jitter (P:PC/RJI)", HFILL }},
791 { &hf_mgcp_param_connectionparam_x,
792 { "Vendor Extension", "mgcp.param.connectionparam.x", FT_STRING, BASE_NONE, NULL, 0x0,
793 "Vendor Extension (P:X-*)", HFILL }},
794 { &hf_mgcp_param_reasoncode,
795 { "ReasonCode (E)", "mgcp.param.reasoncode", FT_STRING, BASE_NONE, NULL, 0x0,
796 "Reason Code", HFILL }},
797 { &hf_mgcp_param_eventstates,
798 { "EventStates (ES)", "mgcp.param.eventstates", FT_STRING, BASE_NONE, NULL, 0x0,
799 "Event States", HFILL }},
800 { &hf_mgcp_param_specificendpoint,
801 { "SpecificEndpointID (Z)", "mgcp.param.specificendpointid", FT_STRING, BASE_NONE, NULL, 0x0,
802 "Specific Endpoint ID", HFILL }},
803 { &hf_mgcp_param_secondendpointid,
804 { "SecondEndpointID (Z2)", "mgcp.param.secondendpointid", FT_STRING, BASE_NONE, NULL, 0x0,
805 "Second Endpoint ID", HFILL }},
806 { &hf_mgcp_param_reqinfo,
807 { "RequestedInfo (F)", "mgcp.param.reqinfo", FT_STRING, BASE_NONE, NULL, 0x0,
808 "Requested Info", HFILL }},
809 { &hf_mgcp_param_quarantinehandling,
810 { "QuarantineHandling (Q)", "mgcp.param.quarantinehandling", FT_STRING, BASE_NONE, NULL, 0x0,
811 "Quarantine Handling", HFILL }},
812 { &hf_mgcp_param_detectedevents,
813 { "DetectedEvents (T)", "mgcp.param.detectedevents", FT_STRING, BASE_NONE, NULL, 0x0,
814 "Detected Events", HFILL }},
815 { &hf_mgcp_param_capabilities,
816 { "Capabilities (A)", "mgcp.param.capabilities", FT_STRING, BASE_NONE, NULL, 0x0,
817 "Capabilities", HFILL }},
818 { &hf_mgcp_param_maxmgcpdatagram,
819 {"MaxMGCPDatagram (MD)", "mgcp.param.maxmgcpdatagram", FT_STRING, BASE_NONE, NULL, 0x0,
820 "Maximum MGCP Datagram size", HFILL }},
821 { &hf_mgcp_param_packagelist,
822 {"PackageList (PL)", "mgcp.param.packagelist", FT_STRING, BASE_NONE, NULL, 0x0,
823 "Package List", HFILL }},
824 { &hf_mgcp_param_extension,
825 { "Extension Parameter (non-critical)", "mgcp.param.extension", FT_STRING, BASE_NONE, NULL, 0x0,
826 "Extension Parameter", HFILL }},
827 { &hf_mgcp_param_extension_critical,
828 { "Extension Parameter (critical)", "mgcp.param.extensioncritical", FT_STRING, BASE_NONE, NULL, 0x0,
829 "Critical Extension Parameter", HFILL }},
830 { &hf_mgcp_param_invalid,
831 { "Invalid Parameter", "mgcp.param.invalid", FT_STRING, BASE_NONE, NULL, 0x0,
833 { &hf_mgcp_messagecount,
834 { "MGCP Message Count", "mgcp.messagecount", FT_UINT32, BASE_DEC, NULL, 0x0,
835 "Number of MGCP message in a packet", HFILL }},
837 { "Duplicate Message", "mgcp.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
840 { "Duplicate Request", "mgcp.req.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
842 { &hf_mgcp_req_dup_frame,
843 { "Original Request Frame", "mgcp.req.dup.frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
844 "Frame containing original request", HFILL }},
846 { "Duplicate Response", "mgcp.rsp.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
848 { &hf_mgcp_rsp_dup_frame,
849 { "Original Response Frame", "mgcp.rsp.dup.frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
850 "Frame containing original response", HFILL }},
857 &ett_mgcp_param_connectionparam,
858 &ett_mgcp_param_localconnectionoptions
861 module_t *mgcp_module;
863 /* Register protocol */
864 proto_mgcp = proto_register_protocol("Media Gateway Control Protocol", "MGCP", "mgcp");
865 proto_register_field_array(proto_mgcp, hf, array_length(hf));
866 proto_register_subtree_array(ett, array_length(ett));
867 register_init_routine(&mgcp_init_protocol);
869 new_register_dissector("mgcp", dissect_mgcp, proto_mgcp);
871 /* Register our configuration options */
872 mgcp_module = prefs_register_protocol(proto_mgcp, proto_reg_handoff_mgcp);
874 prefs_register_uint_preference(mgcp_module, "tcp.gateway_port",
875 "MGCP Gateway TCP Port",
876 "Set the UDP port for gateway messages "
877 "(if other than the default of 2427)",
878 10, &global_mgcp_gateway_tcp_port);
880 prefs_register_uint_preference(mgcp_module, "udp.gateway_port",
881 "MGCP Gateway UDP Port",
882 "Set the TCP port for gateway messages "
883 "(if other than the default of 2427)",
884 10, &global_mgcp_gateway_udp_port);
886 prefs_register_uint_preference(mgcp_module, "tcp.callagent_port",
887 "MGCP Callagent TCP Port",
888 "Set the TCP port for callagent messages "
889 "(if other than the default of 2727)",
890 10, &global_mgcp_callagent_tcp_port);
892 prefs_register_uint_preference(mgcp_module, "udp.callagent_port",
893 "MGCP Callagent UDP Port",
894 "Set the UDP port for callagent messages "
895 "(if other than the default of 2727)",
896 10, &global_mgcp_callagent_udp_port);
899 prefs_register_bool_preference(mgcp_module, "display_raw_text",
900 "Display raw text for MGCP message",
901 "Specifies that the raw text of the "
902 "MGCP message should be displayed "
903 "instead of (or in addition to) the "
905 &global_mgcp_raw_text);
907 prefs_register_obsolete_preference(mgcp_module, "display_dissect_tree");
909 prefs_register_bool_preference(mgcp_module, "display_mgcp_message_count",
910 "Display the number of MGCP messages",
911 "Display the number of MGCP messages "
912 "found in a packet in the protocol column.",
913 &global_mgcp_message_count);
915 mgcp_tap = register_tap("mgcp");
918 /* The registration hand-off routine */
919 void proto_reg_handoff_mgcp(void)
921 static gboolean mgcp_prefs_initialized = FALSE;
922 static dissector_handle_t mgcp_tpkt_handle;
924 * Variables to allow for proper deletion of dissector registration when
925 * the user changes port from the gui.
927 static guint gateway_tcp_port;
928 static guint gateway_udp_port;
929 static guint callagent_tcp_port;
930 static guint callagent_udp_port;
932 if (!mgcp_prefs_initialized)
934 /* Get a handle for the SDP dissector. */
935 sdp_handle = find_dissector("sdp");
936 mgcp_handle = new_create_dissector_handle(dissect_mgcp, proto_mgcp);
937 mgcp_tpkt_handle = new_create_dissector_handle(dissect_tpkt_mgcp, proto_mgcp);
938 mgcp_prefs_initialized = TRUE;
942 dissector_delete_uint("tcp.port", gateway_tcp_port, mgcp_tpkt_handle);
943 dissector_delete_uint("udp.port", gateway_udp_port, mgcp_handle);
944 dissector_delete_uint("tcp.port", callagent_tcp_port, mgcp_tpkt_handle);
945 dissector_delete_uint("udp.port", callagent_udp_port, mgcp_handle);
948 /* Set our port number for future use */
949 gateway_tcp_port = global_mgcp_gateway_tcp_port;
950 gateway_udp_port = global_mgcp_gateway_udp_port;
952 callagent_tcp_port = global_mgcp_callagent_tcp_port;
953 callagent_udp_port = global_mgcp_callagent_udp_port;
955 dissector_add_uint("tcp.port", global_mgcp_gateway_tcp_port, mgcp_tpkt_handle);
956 dissector_add_uint("udp.port", global_mgcp_gateway_udp_port, mgcp_handle);
957 dissector_add_uint("tcp.port", global_mgcp_callagent_tcp_port, mgcp_tpkt_handle);
958 dissector_add_uint("udp.port", global_mgcp_callagent_udp_port, mgcp_handle);
962 * is_mgcp_verb - A function for determining whether there is a
963 * MGCP verb at offset in tvb
966 * tvb - The tvbuff in which we are looking for an MGCP verb
967 * offset - The offset in tvb at which we are looking for a MGCP verb
968 * maxlength - The maximum distance from offset we may look for the
969 * characters that make up a MGCP verb.
970 * verb_name - The name for the verb code found (output)
972 * Return: TRUE if there is an MGCP verb at offset in tvb, otherwise FALSE
974 static gboolean is_mgcp_verb(tvbuff_t *tvb, gint offset, gint maxlength, const gchar **verb_name)
976 int returnvalue = FALSE;
979 /* Read the string into 'word' and see if it looks like the start of a verb */
980 if ((maxlength >= 4) && tvb_get_nstringz0(tvb, offset, sizeof(word), word))
982 if (((g_ascii_strncasecmp(word, "EPCF", 4) == 0) && (*verb_name = "EndpointConfiguration")) ||
983 ((g_ascii_strncasecmp(word, "CRCX", 4) == 0) && (*verb_name = "CreateConnection")) ||
984 ((g_ascii_strncasecmp(word, "MDCX", 4) == 0) && (*verb_name = "ModifyConnection")) ||
985 ((g_ascii_strncasecmp(word, "DLCX", 4) == 0) && (*verb_name = "DeleteConnection")) ||
986 ((g_ascii_strncasecmp(word, "RQNT", 4) == 0) && (*verb_name = "NotificationRequest")) ||
987 ((g_ascii_strncasecmp(word, "NTFY", 4) == 0) && (*verb_name = "Notify")) ||
988 ((g_ascii_strncasecmp(word, "AUEP", 4) == 0) && (*verb_name = "AuditEndpoint")) ||
989 ((g_ascii_strncasecmp(word, "AUCX", 4) == 0) && (*verb_name = "AuditConnection")) ||
990 ((g_ascii_strncasecmp(word, "RSIP", 4) == 0) && (*verb_name = "RestartInProgress")) ||
991 ((g_ascii_strncasecmp(word, "MESG", 4) == 0) && (*verb_name = "Message")) ||
992 (word[0] == 'X' && is_rfc2234_alpha(word[1]) && is_rfc2234_alpha(word[2]) &&
993 is_rfc2234_alpha(word[3]) && (*verb_name = "*Experimental*")))
999 /* May be whitespace after verb code - anything else is an error.. */
1000 if (returnvalue && maxlength >= 5)
1002 char next = tvb_get_guint8(tvb,4);
1003 if ((next != ' ') && (next != '\t'))
1005 returnvalue = FALSE;
1013 * is_mgcp_rspcode - A function for determining whether something which
1014 * looks roughly like a MGCP response code (3-digit number)
1015 * is at 'offset' in tvb
1018 * tvb - The tvbuff in which we are looking for an MGCP response code
1019 * offset - The offset in tvb at which we are looking for a MGCP response code
1020 * maxlength - The maximum distance from offset we may look for the
1021 * characters that make up a MGCP response code.
1023 * Return: TRUE if there is an MGCP response code at offset in tvb,
1026 static gboolean is_mgcp_rspcode(tvbuff_t *tvb, gint offset, gint maxlength)
1028 int returnvalue = FALSE;
1031 /* Do 1st 3 characters look like digits? */
1034 tvb_get_nstringz0(tvb, offset, sizeof(word), word);
1035 if (isdigit(word[0]) && isdigit(word[1]) && isdigit(word[2]))
1041 /* Maybe some white space after the 3rd digit - anything else is an error */
1042 if (returnvalue && maxlength >= 4)
1044 char next = tvb_get_guint8(tvb, 3);
1045 if ((next != ' ') && (next != '\t'))
1047 returnvalue = FALSE;
1055 * is_rfc2234_alpha - Indicates whether the character c is an alphabetical
1056 * character. This function is used instead of
1057 * isalpha because isalpha may deviate from the rfc2234
1058 * definition of ALPHA in some locales.
1061 * c - The character being checked for being an alphabetical character.
1063 * Return: TRUE if c is an upper or lower case alphabetical character,
1066 static gboolean is_rfc2234_alpha(guint8 c)
1068 return ((c <= 'Z' && c >= 'A' ) || (c <= 'z' && c >= 'a'));
1073 * tvb_parse_param - Parse the MGCP param into a type and a value.
1076 * tvb - The tvbuff containing the MGCP param we are to parse.
1077 * offset - The offset in tvb at which we will begin looking for a
1078 * MGCP parameter to parse.
1079 * len - The maximum distance from offset in tvb that we can look for
1080 * an MGCP parameter to parse.
1081 * hf - The place to write a pointer to the integer representing the
1082 * header field associated with the MGCP parameter parsed.
1084 * Returns: The offset in tvb where the value of the MGCP parameter
1087 static gint tvb_parse_param(tvbuff_t* tvb, gint offset, gint len, int** hf)
1089 gint returnvalue = -1, tvb_current_offset,counter;
1090 guint8 tempchar, plus_minus;
1093 tvb_current_offset = offset;
1099 tempchar = tvb_get_guint8(tvb,tvb_current_offset);
1104 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1106 *hf = &hf_mgcp_param_invalid;
1109 *hf = &hf_mgcp_param_rspack;
1112 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1114 *hf = &hf_mgcp_param_invalid;
1117 *hf = &hf_mgcp_param_bearerinfo;
1120 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1122 *hf = &hf_mgcp_param_invalid;
1125 *hf = &hf_mgcp_param_callid;
1128 tvb_current_offset++;
1129 if (len > (tvb_current_offset - offset) &&
1130 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1132 *hf = &hf_mgcp_param_connectionid;
1133 tvb_current_offset--;
1136 if (tempchar == '2')
1138 *hf = &hf_mgcp_param_secondconnectionid;
1142 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1144 *hf = &hf_mgcp_param_invalid;
1147 *hf = &hf_mgcp_param_notifiedentity;
1151 tvb_current_offset++;
1153 /* X: is RequestIdentifier */
1154 if (len > (tvb_current_offset - offset) &&
1155 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1157 *hf = &hf_mgcp_param_requestid;
1158 tvb_current_offset--;
1161 /* X+...: or X-....: are vendor extension parameters */
1163 if (len > (tvb_current_offset - offset) &&
1164 ((plus_minus = tvb_get_guint8(tvb,tvb_current_offset)) == '-' ||
1165 (plus_minus == '+')))
1167 /* Move past + or - */
1168 tvb_current_offset++;
1170 /* Keep going, through possible vendor param name */
1172 ((len > (counter + tvb_current_offset-offset)) &&
1173 (is_rfc2234_alpha(tempchar = tvb_get_guint8(tvb, tvb_current_offset+counter)) ||
1174 isdigit(tempchar))) ;
1177 if (tempchar == ':')
1179 /* Looks like a valid vendor param name */
1180 tvb_current_offset += counter;
1184 *hf = &hf_mgcp_param_extension_critical;
1187 *hf = &hf_mgcp_param_extension;
1194 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1196 *hf = &hf_mgcp_param_invalid;
1199 *hf = &hf_mgcp_param_localconnoptions;
1202 tvb_current_offset++;
1203 if (len > (tvb_current_offset - offset) &&
1204 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1206 *hf = &hf_mgcp_param_connectionmode;
1207 tvb_current_offset--;
1210 if (tempchar == 'D')
1212 *hf = &hf_mgcp_param_maxmgcpdatagram;
1216 tvb_current_offset++;
1217 if (len > (tvb_current_offset - offset) &&
1218 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1220 *hf = &hf_mgcp_param_reqevents;
1221 tvb_current_offset--;
1224 if ( tempchar == 'M')
1226 *hf = &hf_mgcp_param_restartmethod;
1229 if (tempchar == 'D')
1231 *hf = &hf_mgcp_param_restartdelay;
1235 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1237 *hf = &hf_mgcp_param_invalid;
1240 *hf = &hf_mgcp_param_signalreq;
1241 buf = &(mi->signalReq);
1244 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1246 *hf = &hf_mgcp_param_invalid;
1249 *hf = &hf_mgcp_param_digitmap;
1250 mi->hasDigitMap = TRUE;
1253 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1255 *hf = &hf_mgcp_param_invalid;
1258 *hf = &hf_mgcp_param_observedevent;
1259 buf = &(mi->observedEvents);
1262 tvb_current_offset++;
1263 if (len > (tvb_current_offset - offset) &&
1264 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1266 *hf = &hf_mgcp_param_connectionparam;
1267 tvb_current_offset--;
1270 if ( tempchar == 'L')
1272 *hf = &hf_mgcp_param_packagelist;
1276 tvb_current_offset++;
1277 if (len > (tvb_current_offset - offset) &&
1278 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1280 *hf = &hf_mgcp_param_reasoncode;
1281 tvb_current_offset--;
1284 if ( tempchar == 'S')
1286 *hf = &hf_mgcp_param_eventstates;
1290 tvb_current_offset++;
1291 if (len > (tvb_current_offset - offset) &&
1292 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1294 *hf = &hf_mgcp_param_specificendpoint;
1295 tvb_current_offset--;
1298 if (tempchar == '2')
1300 *hf = &hf_mgcp_param_secondendpointid;
1304 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1306 *hf = &hf_mgcp_param_invalid;
1309 *hf = &hf_mgcp_param_reqinfo;
1312 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1314 *hf = &hf_mgcp_param_invalid;
1317 *hf = &hf_mgcp_param_quarantinehandling;
1320 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1322 *hf = &hf_mgcp_param_invalid;
1325 *hf = &hf_mgcp_param_detectedevents;
1328 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1330 *hf = &hf_mgcp_param_invalid;
1333 *hf = &hf_mgcp_param_capabilities;
1337 *hf = &hf_mgcp_param_invalid;
1341 /* Move to (hopefully) the colon */
1342 tvb_current_offset++;
1344 /* Add a recognised parameter type if we have one */
1345 if (*hf != NULL && len > (tvb_current_offset - offset) &&
1346 tvb_get_guint8(tvb,tvb_current_offset) == ':')
1348 tvb_current_offset++;
1349 tvb_current_offset = tvb_skip_wsp(tvb,tvb_current_offset, (len - tvb_current_offset + offset));
1350 returnvalue = tvb_current_offset;
1352 /* set the observedEvents or signalReq used in Voip Calls analysis */
1354 *buf = tvb_get_ephemeral_string(tvb, tvb_current_offset, (len - tvb_current_offset + offset));
1360 /* Was an empty line */
1361 *hf = &hf_mgcp_param_invalid;
1364 /* For these types, show the whole line */
1365 if ((*hf == &hf_mgcp_param_invalid) ||
1366 (*hf == &hf_mgcp_param_extension) || (*hf == &hf_mgcp_param_extension_critical))
1368 returnvalue = offset;
1376 * dissect_mgcp_firstline - Dissects the firstline of an MGCP message.
1377 * Adds the appropriate headers fields to
1378 * tree for the dissection of the first line
1379 * of an MGCP message.
1382 * tvb - The tvb containing the first line of an MGCP message. This
1383 * tvb is presumed to ONLY contain the first line of the MGCP
1385 * pinfo - The packet info for the packet. This is not really used
1386 * by this function but is passed through so as to retain the
1387 * style of a dissector.
1388 * tree - The tree from which to hang the structured information parsed
1389 * from the first line of the MGCP message.
1391 static void dissect_mgcp_firstline(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1393 gint tvb_current_offset,tvb_previous_offset,tvb_len,tvb_current_len;
1394 gint tokennum, tokenlen;
1395 proto_item* hidden_item;
1396 char *transid = NULL;
1398 char *endpointId = NULL;
1399 mgcp_type_t mgcp_type = MGCP_OTHERS;
1400 conversation_t* conversation;
1401 mgcp_call_info_key mgcp_call_key;
1402 mgcp_call_info_key *new_mgcp_call_key = NULL;
1403 mgcp_call_t *mgcp_call = NULL;
1406 const gchar *verb_description = "";
1407 char code_with_verb[64] = ""; /* To fit "<4-letter-code> (<longest-verb>)" */
1409 static address null_address = { AT_NONE, -1, 0, NULL };
1410 tvb_previous_offset = 0;
1411 tvb_len = tvb_length(tvb);
1412 tvb_current_len = tvb_len;
1413 tvb_current_offset = tvb_previous_offset;
1414 mi->is_duplicate = FALSE;
1415 mi->request_available = FALSE;
1423 tvb_current_len = tvb_length_remaining(tvb,tvb_previous_offset);
1424 tvb_current_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_current_len, ' ');
1425 if (tvb_current_offset == -1)
1427 tvb_current_offset = tvb_len;
1428 tokenlen = tvb_current_len;
1432 tokenlen = tvb_current_offset - tvb_previous_offset;
1437 THROW(ReportedBoundsError);
1438 code = tvb_format_text(tvb,tvb_previous_offset,tokenlen);
1439 g_strlcpy(mi->code,code,5);
1440 if (is_mgcp_verb(tvb,tvb_previous_offset,tvb_current_len,&verb_description))
1442 mgcp_type = MGCP_REQUEST;
1443 if (verb_description != NULL)
1445 /* Can show verb along with code if known */
1446 g_snprintf(code_with_verb, 64, "%s (%s)", code, verb_description);
1449 proto_tree_add_string_format(tree, hf_mgcp_req_verb, tvb,
1450 tvb_previous_offset, tokenlen,
1452 strlen(code_with_verb) ? code_with_verb : code);
1455 if (is_mgcp_rspcode(tvb,tvb_previous_offset,tvb_current_len))
1457 mgcp_type = MGCP_RESPONSE;
1458 rspcode = atoi(code);
1459 mi->rspcode = rspcode;
1460 proto_tree_add_uint(tree,hf_mgcp_rsp_rspcode, tvb,
1461 tvb_previous_offset, tokenlen, rspcode);
1470 transid = tvb_format_text(tvb,tvb_previous_offset,tokenlen);
1471 /* XXX - what if this isn't a valid text string? */
1472 mi->transid = (guint32)strtoul(transid, NULL, 10);
1473 proto_tree_add_string(tree, hf_mgcp_transid, tvb,
1474 tvb_previous_offset, tokenlen, transid);
1478 if (mgcp_type == MGCP_REQUEST)
1480 endpointId = tvb_format_text(tvb, tvb_previous_offset,tokenlen);
1481 mi->endpointId = ep_strdup(endpointId);
1482 proto_tree_add_string(tree,hf_mgcp_req_endpoint, tvb,
1483 tvb_previous_offset, tokenlen, endpointId);
1486 if (mgcp_type == MGCP_RESPONSE)
1488 if (tvb_current_offset < tvb_len)
1490 tokenlen = tvb_find_line_end(tvb, tvb_previous_offset,
1491 -1, &tvb_current_offset, FALSE);
1495 tokenlen = tvb_current_len;
1497 proto_tree_add_string(tree, hf_mgcp_rsp_rspstring, tvb,
1498 tvb_previous_offset, tokenlen,
1499 tvb_format_text(tvb, tvb_previous_offset,
1505 if ((tokennum == 3 && mgcp_type == MGCP_REQUEST))
1507 if (tvb_current_offset < tvb_len )
1509 tokenlen = tvb_find_line_end(tvb, tvb_previous_offset,
1510 -1, &tvb_current_offset,FALSE);
1514 tokenlen = tvb_current_len;
1516 proto_tree_add_string(tree,hf_mgcp_version, tvb,
1517 tvb_previous_offset, tokenlen,
1518 tvb_format_text(tvb,tvb_previous_offset,
1522 if (tvb_current_offset < tvb_len)
1524 tvb_previous_offset = tvb_skip_wsp(tvb, tvb_current_offset,
1528 } while (tvb_current_offset < tvb_len && tvb_previous_offset < tvb_len && tokennum <= 3);
1533 hidden_item = proto_tree_add_boolean(tree, hf_mgcp_rsp, tvb, 0, 0, TRUE);
1534 PROTO_ITEM_SET_HIDDEN(hidden_item);
1535 /* Check for MGCP response. A response must match a call that
1536 we've seen, and the response must be sent to the same
1537 port and address that the call came from, and must
1538 come from the port to which the call was sent.
1540 If the transport is connection-oriented (we check, for
1541 now, only for "pinfo->ptype" of PT_TCP), we take
1542 into account the address from which the call was sent
1543 and the address to which the call was sent, because
1544 the addresses of the two endpoints should be the same
1545 for all calls and replies.
1547 If the transport is connectionless, we don't worry
1548 about the address to which the call was sent and from
1549 which the reply was sent, because there's no
1550 guarantee that the reply will come from the address
1551 to which the call was sent. */
1552 if (pinfo->ptype == PT_TCP)
1554 conversation = find_conversation(pinfo->fd->num, &pinfo->src,
1555 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1556 pinfo->destport, 0);
1560 /* XXX - can we just use NO_ADDR_B? Unfortunately,
1561 * you currently still have to pass a non-null
1562 * pointer for the second address argument even
1565 conversation = find_conversation(pinfo->fd->num, &null_address,
1566 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1567 pinfo->destport, 0);
1569 if (conversation != NULL)
1571 /* Look only for matching request, if
1572 matching conversation is available. */
1573 mgcp_call_key.transid = mi->transid;
1574 mgcp_call_key.conversation = conversation;
1575 mgcp_call = (mgcp_call_t *)g_hash_table_lookup(mgcp_calls, &mgcp_call_key);
1578 /* Indicate the frame to which this is a reply. */
1579 if (mgcp_call->req_num)
1582 mi->request_available = TRUE;
1583 mgcp_call->responded = TRUE;
1584 mi->req_num = mgcp_call->req_num;
1585 g_strlcpy(mi->code,mgcp_call->code,5);
1586 item = proto_tree_add_uint_format(tree, hf_mgcp_req_frame,
1587 tvb, 0, 0, mgcp_call->req_num,
1588 "This is a response to a request in frame %u",
1589 mgcp_call->req_num);
1590 PROTO_ITEM_SET_GENERATED(item);
1591 nstime_delta(&delta, &pinfo->fd->abs_ts, &mgcp_call->req_time);
1592 item = proto_tree_add_time(tree, hf_mgcp_time, tvb, 0, 0, &delta);
1593 PROTO_ITEM_SET_GENERATED(item);
1596 if (mgcp_call->rsp_num == 0)
1598 /* We have not yet seen a response to that call, so
1599 this must be the first response; remember its
1601 mgcp_call->rsp_num = pinfo->fd->num;
1605 /* We have seen a response to this call - but was it
1606 *this* response? (disregard provisional responses) */
1607 if ((mgcp_call->rsp_num != pinfo->fd->num) &&
1608 (mi->rspcode >= 200) &&
1609 (mi->rspcode == mgcp_call->rspcode))
1611 /* No, so it's a duplicate response. Mark it as such. */
1612 mi->is_duplicate = TRUE;
1613 col_append_fstr(pinfo->cinfo, COL_INFO,
1614 ", Duplicate Response %u",
1619 item = proto_tree_add_uint(tree, hf_mgcp_dup, tvb, 0,0, mi->transid);
1620 PROTO_ITEM_SET_HIDDEN(item);
1621 item = proto_tree_add_uint(tree, hf_mgcp_rsp_dup,
1622 tvb, 0, 0, mi->transid);
1623 PROTO_ITEM_SET_GENERATED(item);
1624 item = proto_tree_add_uint(tree, hf_mgcp_rsp_dup_frame,
1625 tvb, 0, 0, mgcp_call->rsp_num);
1626 PROTO_ITEM_SET_GENERATED(item);
1630 /* Now store the response code (after comparison above) */
1631 mgcp_call->rspcode = mi->rspcode;
1636 hidden_item = proto_tree_add_boolean(tree, hf_mgcp_req, tvb, 0, 0, TRUE);
1637 PROTO_ITEM_SET_HIDDEN(hidden_item);
1638 /* Keep track of the address and port whence the call came,
1639 * and the port to which the call is being sent, so that
1640 * we can match up calls with replies.
1642 * If the transport is connection-oriented (we check, for
1643 * now, only for "pinfo->ptype" of PT_TCP), we take
1644 * into account the address from which the call was sent
1645 * and the address to which the call was sent, because
1646 * the addresses of the two endpoints should be the same
1647 * for all calls and replies.
1649 * If the transport is connectionless, we don't worry
1650 * about the address to which the call was sent and from
1651 * which the reply was sent, because there's no
1652 * guarantee that the reply will come from the address
1653 * to which the call was sent.
1655 if (pinfo->ptype == PT_TCP)
1657 conversation = find_conversation(pinfo->fd->num, &pinfo->src,
1658 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1659 pinfo->destport, 0);
1664 * XXX - can we just use NO_ADDR_B? Unfortunately,
1665 * you currently still have to pass a non-null
1666 * pointer for the second address argument even
1669 conversation = find_conversation(pinfo->fd->num, &pinfo->src,
1670 &null_address, pinfo->ptype, pinfo->srcport,
1671 pinfo->destport, 0);
1673 if (conversation == NULL)
1675 /* It's not part of any conversation - create a new one. */
1676 if (pinfo->ptype == PT_TCP)
1678 conversation = conversation_new(pinfo->fd->num, &pinfo->src,
1679 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1680 pinfo->destport, 0);
1684 conversation = conversation_new(pinfo->fd->num, &pinfo->src,
1685 &null_address, pinfo->ptype, pinfo->srcport,
1686 pinfo->destport, 0);
1690 /* Prepare the key data */
1691 mgcp_call_key.transid = mi->transid;
1692 mgcp_call_key.conversation = conversation;
1694 /* Look up the request */
1695 mgcp_call = (mgcp_call_t *)g_hash_table_lookup(mgcp_calls, &mgcp_call_key);
1696 if (mgcp_call != NULL)
1698 /* We've seen a request with this TRANSID, with the same
1699 source and destination, before - but was it
1701 if (pinfo->fd->num != mgcp_call->req_num)
1703 /* No, so it's a duplicate request. Mark it as such. */
1704 mi->is_duplicate = TRUE;
1705 mi->req_num = mgcp_call->req_num;
1706 col_append_fstr(pinfo->cinfo, COL_INFO,
1707 ", Duplicate Request %u",
1712 item = proto_tree_add_uint(tree, hf_mgcp_dup, tvb, 0,0, mi->transid);
1713 PROTO_ITEM_SET_HIDDEN(item);
1714 item = proto_tree_add_uint(tree, hf_mgcp_req_dup, tvb, 0,0, mi->transid);
1715 PROTO_ITEM_SET_GENERATED(item);
1716 item = proto_tree_add_uint(tree, hf_mgcp_req_dup_frame, tvb, 0,0, mi->req_num);
1717 PROTO_ITEM_SET_GENERATED(item);
1723 /* Prepare the value data.
1724 "req_num" and "rsp_num" are frame numbers;
1725 frame numbers are 1-origin, so we use 0
1726 to mean "we don't yet know in which frame
1727 the reply for this call appears". */
1728 new_mgcp_call_key = (mgcp_call_info_key *)se_alloc(sizeof(*new_mgcp_call_key));
1729 *new_mgcp_call_key = mgcp_call_key;
1730 mgcp_call = (mgcp_call_t *)se_alloc(sizeof(*mgcp_call));
1731 mgcp_call->req_num = pinfo->fd->num;
1732 mgcp_call->rsp_num = 0;
1733 mgcp_call->transid = mi->transid;
1734 mgcp_call->responded = FALSE;
1735 mgcp_call->req_time=pinfo->fd->abs_ts;
1736 g_strlcpy(mgcp_call->code,mi->code,5);
1739 g_hash_table_insert(mgcp_calls, new_mgcp_call_key, mgcp_call);
1741 if (mgcp_call->rsp_num)
1743 proto_item* item = proto_tree_add_uint_format(tree, hf_mgcp_rsp_frame,
1744 tvb, 0, 0, mgcp_call->rsp_num,
1745 "The response to this request is in frame %u",
1746 mgcp_call->rsp_num);
1747 PROTO_ITEM_SET_GENERATED(item);
1754 mi->mgcp_type = mgcp_type;
1757 mi->req_time.secs=mgcp_call->req_time.secs;
1758 mi->req_time.nsecs=mgcp_call->req_time.nsecs;
1762 tap_queue_packet(mgcp_tap, pinfo, mi);
1766 * dissect_mgcp_params - Dissects the parameters of an MGCP message.
1767 * Adds the appropriate headers fields to
1768 * tree for the dissection of the parameters
1769 * of an MGCP message.
1772 * tvb - The tvb containing the parameters of an MGCP message. This
1773 * tvb is presumed to ONLY contain the part of the MGCP
1774 * message which contains the MGCP parameters.
1775 * tree - The tree from which to hang the structured information parsed
1776 * from the parameters of the MGCP message.
1778 static void dissect_mgcp_params(tvbuff_t *tvb, proto_tree *tree)
1780 int linelen, tokenlen, *my_param;
1781 gint tvb_lineend, tvb_linebegin, tvb_len, old_lineend;
1782 gint tvb_tokenbegin;
1783 proto_tree *mgcp_param_ti, *mgcp_param_tree;
1785 tvb_len = tvb_length(tvb);
1787 tvb_lineend = tvb_linebegin;
1791 mgcp_param_ti = proto_tree_add_item(tree, hf_mgcp_params, tvb,
1792 tvb_linebegin, tvb_len, ENC_NA);
1793 proto_item_set_text(mgcp_param_ti, "Parameters");
1794 mgcp_param_tree = proto_item_add_subtree(mgcp_param_ti, ett_mgcp_param);
1796 /* Parse the parameters */
1797 while (tvb_lineend < tvb_len)
1799 old_lineend = tvb_lineend;
1800 linelen = tvb_find_line_end(tvb, tvb_linebegin, -1,&tvb_lineend,FALSE);
1801 tvb_tokenbegin = tvb_parse_param(tvb, tvb_linebegin, linelen, &my_param);
1805 if (*my_param == hf_mgcp_param_connectionparam)
1807 tokenlen = tvb_find_line_end(tvb,tvb_tokenbegin,-1,&tvb_lineend,FALSE);
1808 dissect_mgcp_connectionparams(mgcp_param_tree, tvb, tvb_linebegin,
1809 tvb_tokenbegin - tvb_linebegin, tokenlen);
1812 if (*my_param == hf_mgcp_param_localconnoptions)
1814 tokenlen = tvb_find_line_end(tvb,tvb_tokenbegin,-1,&tvb_lineend,FALSE);
1815 dissect_mgcp_localconnectionoptions(mgcp_param_tree, tvb, tvb_linebegin,
1816 tvb_tokenbegin - tvb_linebegin, tokenlen);
1820 tokenlen = tvb_find_line_end(tvb,tvb_tokenbegin,-1,&tvb_lineend,FALSE);
1821 proto_tree_add_string(mgcp_param_tree,*my_param, tvb,
1822 tvb_linebegin, linelen,
1823 tvb_format_text(tvb,tvb_tokenbegin, tokenlen));
1827 tvb_linebegin = tvb_lineend;
1828 /* Its a infinite loop if we didn't advance (or went backwards) */
1829 if (old_lineend >= tvb_lineend)
1831 THROW(ReportedBoundsError);
1837 /* Dissect the connection params */
1839 dissect_mgcp_connectionparams(proto_tree *parent_tree, tvbuff_t *tvb, gint offset, gint param_type_len, gint param_val_len)
1841 proto_tree *tree = parent_tree;
1842 proto_item *item = NULL;
1844 gchar *tokenline = NULL;
1845 gchar **tokens = NULL;
1846 gchar **typval = NULL;
1854 item = proto_tree_add_item(parent_tree, hf_mgcp_param_connectionparam, tvb, offset, param_type_len+param_val_len, ENC_ASCII|ENC_NA);
1855 tree = proto_item_add_subtree(item, ett_mgcp_param_connectionparam);
1859 offset += param_type_len; /* skip the P: */
1860 tokenline = tvb_get_ephemeral_string(tvb, offset, param_val_len);
1862 /* Split into type=value pairs separated by comma */
1863 tokens = ep_strsplit(tokenline, ",", -1);
1865 for (i = 0; tokens[i] != NULL; i++)
1867 tokenlen = (int)strlen(tokens[i]);
1868 typval = ep_strsplit(tokens[i], "=", 2);
1869 if ((typval[0] != NULL) && (typval[1] != NULL))
1871 if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PS"))
1873 hf_uint = hf_mgcp_param_connectionparam_ps;
1875 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "OS"))
1877 hf_uint = hf_mgcp_param_connectionparam_os;
1879 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PR"))
1881 hf_uint = hf_mgcp_param_connectionparam_pr;
1883 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "OR"))
1885 hf_uint = hf_mgcp_param_connectionparam_or;
1887 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PL"))
1889 hf_uint = hf_mgcp_param_connectionparam_pl;
1891 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "JI"))
1893 hf_uint = hf_mgcp_param_connectionparam_ji;
1895 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "LA"))
1897 hf_uint = hf_mgcp_param_connectionparam_la;
1899 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PC/RPS"))
1901 hf_uint = hf_mgcp_param_connectionparam_pcrps;
1902 } else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PC/ROS"))
1904 hf_uint = hf_mgcp_param_connectionparam_pcros;
1906 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PC/RPL"))
1908 hf_uint = hf_mgcp_param_connectionparam_pcrpl;
1910 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PC/RJI"))
1912 hf_uint = hf_mgcp_param_connectionparam_pcrji;
1914 else if (!g_ascii_strncasecmp(g_strstrip(typval[0]), "X-", 2))
1916 hf_string = hf_mgcp_param_connectionparam_x;
1928 proto_tree_add_uint(tree, hf_uint, tvb, offset, tokenlen, (guint32)strtoul(typval[1], NULL, 10));
1930 else if (hf_string != -1)
1932 proto_tree_add_string(tree, hf_string, tvb, offset, tokenlen, g_strstrip(typval[1]));
1936 proto_tree_add_text(tree, tvb, offset, tokenlen, "Unknown parameter: %s", tokens[i]);
1942 proto_tree_add_text(tree, tvb, offset, tokenlen, "Malformed parameter: %s", tokens[i]);
1944 offset += tokenlen + 1; /* 1 extra for the delimiter */
1949 /* Dissect the local connection option */
1951 dissect_mgcp_localconnectionoptions(proto_tree *parent_tree, tvbuff_t *tvb, gint offset, gint param_type_len, gint param_val_len)
1953 proto_tree *tree = parent_tree;
1954 proto_item *item = NULL;
1956 gchar *tokenline = NULL;
1957 gchar **tokens = NULL;
1958 gchar **typval = NULL;
1966 item = proto_tree_add_item(parent_tree, hf_mgcp_param_localconnoptions, tvb, offset, param_type_len+param_val_len, ENC_ASCII|ENC_NA);
1967 tree = proto_item_add_subtree(item, ett_mgcp_param_localconnectionoptions);
1971 offset += param_type_len; /* skip the L: */
1972 tokenline = tvb_get_ephemeral_string(tvb, offset, param_val_len);
1974 /* Split into type=value pairs separated by comma */
1975 tokens = ep_strsplit(tokenline, ",", -1);
1976 for (i = 0; tokens[i] != NULL; i++)
1981 tokenlen = (int)strlen(tokens[i]);
1982 typval = ep_strsplit(tokens[i], ":", 2);
1983 if ((typval[0] != NULL) && (typval[1] != NULL))
1985 if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "p"))
1987 hf_uint = hf_mgcp_param_localconnoptions_p;
1989 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "a"))
1991 hf_string = hf_mgcp_param_localconnoptions_a;
1993 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "s"))
1995 hf_string = hf_mgcp_param_localconnoptions_s;
1997 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "e"))
1999 hf_string = hf_mgcp_param_localconnoptions_e;
2001 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "sc-rtp"))
2003 hf_string = hf_mgcp_param_localconnoptions_scrtp;
2005 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "sc-rtcp"))
2007 hf_string = hf_mgcp_param_localconnoptions_scrtcp;
2009 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "b"))
2011 hf_string = hf_mgcp_param_localconnoptions_b;
2013 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "es-ccd"))
2015 hf_string = hf_mgcp_param_localconnoptions_esccd;
2017 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "es-cci"))
2019 hf_string = hf_mgcp_param_localconnoptions_escci;
2021 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "dq-gi"))
2023 hf_string = hf_mgcp_param_localconnoptions_dqgi;
2025 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "dq-rd"))
2027 hf_string = hf_mgcp_param_localconnoptions_dqrd;
2029 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "dq-ri"))
2031 hf_string = hf_mgcp_param_localconnoptions_dqri;
2033 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "dq-rr"))
2035 hf_string = hf_mgcp_param_localconnoptions_dqrr;
2037 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "k"))
2039 hf_string = hf_mgcp_param_localconnoptions_k;
2041 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "gc"))
2043 hf_uint = hf_mgcp_param_localconnoptions_gc;
2045 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "fmtp"))
2047 hf_string = hf_mgcp_param_localconnoptions_fmtp;
2049 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "nt"))
2051 hf_string = hf_mgcp_param_localconnoptions_nt;
2053 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "o-fmtp"))
2055 hf_string = hf_mgcp_param_localconnoptions_ofmtp;
2057 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "r"))
2059 hf_string = hf_mgcp_param_localconnoptions_r;
2061 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "t"))
2063 hf_string = hf_mgcp_param_localconnoptions_t;
2065 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "r-cnf"))
2067 hf_string = hf_mgcp_param_localconnoptions_rcnf;
2069 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "r-dir"))
2071 hf_string = hf_mgcp_param_localconnoptions_rdir;
2073 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "r-sh"))
2075 hf_string = hf_mgcp_param_localconnoptions_rsh;
2077 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "mp"))
2079 hf_string = hf_mgcp_param_localconnoptions_mp;
2081 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "fxr/fx"))
2083 hf_string = hf_mgcp_param_localconnoptions_fxr;
2096 proto_tree_add_uint(tree, hf_uint, tvb, offset, tokenlen, (guint32)strtoul(typval[1], NULL, 10));
2098 else if (hf_string != -1)
2100 proto_tree_add_string(tree, hf_string, tvb, offset, tokenlen, g_strstrip(typval[1]));
2104 proto_tree_add_text(tree, tvb, offset, tokenlen, "Unknown parameter: %s", tokens[i]);
2110 proto_tree_add_text(tree, tvb, offset, tokenlen, "Malformed parameter: %s", tokens[i]);
2112 offset += tokenlen + 1; /* 1 extra for the delimiter */
2119 * tvb_find_null_line - Returns the length from offset to the first null
2120 * line found (a null line is a line that begins
2121 * with a CR or LF. The offset to the first character
2122 * after the null line is written into the gint pointed
2123 * to by next_offset.
2126 * tvb - The tvbuff in which we are looking for a null line.
2127 * offset - The offset in tvb at which we will begin looking for
2129 * len - The maximum distance from offset in tvb that we will look for
2130 * a null line. If it is -1 we will look to the end of the buffer.
2132 * next_offset - The location to write the offset of first character
2133 * FOLLOWING the null line.
2135 * Returns: The length from offset to the first character BEFORE
2138 static gint tvb_find_null_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset)
2140 gint tvb_lineend,tvb_current_len,tvb_linebegin,maxoffset;
2143 tvb_linebegin = offset;
2144 tvb_lineend = tvb_linebegin;
2146 /* Simple setup to allow for the traditional -1 search to the end of the tvbuff */
2149 tvb_current_len = len;
2153 tvb_current_len = tvb_length_remaining(tvb,offset);
2156 maxoffset = (tvb_current_len - 1) + offset;
2158 /* Loop around until we either find a line beginning with a carriage return
2159 or newline character or until we hit the end of the tvbuff. */
2162 tvb_linebegin = tvb_lineend;
2163 tvb_current_len = tvb_length_remaining(tvb,tvb_linebegin);
2164 tvb_find_line_end(tvb, tvb_linebegin, tvb_current_len, &tvb_lineend,FALSE);
2165 tempchar = tvb_get_guint8(tvb,tvb_linebegin);
2166 } while (tempchar != '\r' && tempchar != '\n' && tvb_lineend <= maxoffset);
2169 *next_offset = tvb_lineend;
2171 if (tvb_lineend <= maxoffset)
2173 tvb_current_len = tvb_linebegin - offset;
2177 tvb_current_len = tvb_length_remaining(tvb,offset);
2180 return tvb_current_len;
2184 * tvb_find_dot_line - Returns the length from offset to the first line
2185 * containing only a dot (.) character. A line
2186 * containing only a dot is used to indicate a
2187 * separation between multiple MGCP messages
2188 * piggybacked in the same UDP packet.
2191 * tvb - The tvbuff in which we are looking for a dot line.
2192 * offset - The offset in tvb at which we will begin looking for
2194 * len - The maximum distance from offset in tvb that we will look for
2195 * a dot line. If it is -1 we will look to the end of the buffer.
2197 * next_offset - The location to write the offset of first character
2198 * FOLLOWING the dot line.
2200 * Returns: The length from offset to the first character BEFORE
2201 * the dot line or -1 if the character at offset is a .
2202 * followed by a newline or a carriage return.
2204 static gint tvb_find_dot_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset)
2206 gint tvb_current_offset, tvb_current_len, maxoffset,tvb_len;
2208 tvb_current_offset = offset;
2209 tvb_current_len = len;
2210 tvb_len = tvb_length(tvb);
2214 maxoffset = tvb_len - 1;
2218 maxoffset = (len - 1) + offset;
2220 tvb_current_offset = offset -1;
2224 tvb_current_offset = tvb_find_guint8(tvb, tvb_current_offset+1,
2225 tvb_current_len, '.');
2226 tvb_current_len = maxoffset - tvb_current_offset + 1;
2228 /* If we didn't find a . then break out of the loop */
2229 if (tvb_current_offset == -1)
2234 /* Do we have and characters following the . ? */
2235 if (tvb_current_offset < maxoffset)
2237 tempchar = tvb_get_guint8(tvb,tvb_current_offset+1);
2238 /* Are the characters that follow the dot a newline or carriage return ? */
2239 if (tempchar == '\r' || tempchar == '\n')
2241 /* Do we have any charaters that proceed the . ? */
2242 if (tvb_current_offset == 0)
2248 tempchar = tvb_get_guint8(tvb,tvb_current_offset-1);
2250 /* Are the characters that follow the dot a newline or a
2251 carriage return ? */
2252 if (tempchar == '\r' || tempchar == '\n')
2260 if (tvb_current_offset == maxoffset)
2262 if (tvb_current_offset == 0)
2268 tempchar = tvb_get_guint8(tvb,tvb_current_offset-1);
2269 if (tempchar == '\r' || tempchar == '\n')
2275 } while (tvb_current_offset < maxoffset);
2279 * So now we either have the tvb_current_offset of a . in a dot line
2280 * or a tvb_current_offset of -1
2282 if (tvb_current_offset == -1)
2284 tvb_current_offset = maxoffset +1;
2285 *next_offset = maxoffset + 1;
2289 tvb_find_line_end(tvb,tvb_current_offset,tvb_current_len,next_offset,FALSE);
2292 if (tvb_current_offset == offset)
2294 tvb_current_len = -1;
2298 tvb_current_len = tvb_current_offset - offset;
2301 return tvb_current_len;