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.
43 #include <epan/packet.h>
44 #include <epan/emem.h>
45 #include <epan/proto.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, tvb_current_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);
344 tvb_current_len = tvb_len;
350 * Check to see whether we're really dealing with MGCP by looking
351 * for a valid MGCP verb or response code. This isn't infallible,
352 * but its cheap and its better than nothing.
354 if (is_mgcp_verb(tvb,0,tvb_len, &verb_name) || is_mgcp_rspcode(tvb,0,tvb_len))
357 * Set the columns now, so that they'll be set correctly if we throw
358 * an exception. We can set them later as well....
360 col_set_str(pinfo->cinfo, COL_PROTOCOL, "MGCP");
361 col_clear(pinfo->cinfo, COL_INFO);
364 * Loop through however many mgcp messages may be stuck in
365 * this packet using piggybacking
372 /* Create our mgcp subtree */
373 ti = proto_tree_add_item(tree,proto_mgcp,tvb,0,0, FALSE);
374 mgcp_tree = proto_item_add_subtree(ti, ett_mgcp);
377 sectionlen = tvb_find_dot_line(tvb, tvb_sectionbegin, -1, &tvb_sectionend);
378 if (sectionlen != -1)
380 dissect_mgcp_message(tvb_new_subset(tvb, tvb_sectionbegin,
382 pinfo, tree, mgcp_tree,ti);
383 tvb_sectionbegin = tvb_sectionend;
389 } while (tvb_sectionend < tvb_len);
393 proto_item *tii = proto_tree_add_uint(mgcp_tree, hf_mgcp_messagecount, tvb,
394 0 ,0 , num_messages);
395 PROTO_ITEM_SET_HIDDEN(tii);
399 * Add our column information after dissecting SDP
400 * in order to prevent the column info changing to reflect the SDP
401 * (when showing message count)
403 tvb_sectionbegin = 0;
404 if (global_mgcp_message_count == TRUE )
406 if (num_messages > 1)
408 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "MGCP (%i messages)",num_messages);
412 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "MGCP (%i message)",num_messages);
416 sectionlen = tvb_find_line_end(tvb, tvb_sectionbegin,-1,
417 &tvb_sectionend,FALSE);
418 col_prepend_fstr(pinfo->cinfo, COL_INFO, "%s",
419 tvb_format_text(tvb, tvb_sectionbegin, sectionlen));
426 /************************************************************************
427 * dissect_tpkt_mgcp - The dissector for the ASCII TPKT Media Gateway Control Protocol
428 ************************************************************************/
429 static int dissect_tpkt_mgcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
434 /* Check whether this looks like a ASCII TPKT-encapsulated
437 ascii_tpkt = is_asciitpkt(tvb);
439 if (ascii_tpkt != 1 )
442 * It's not a ASCII TPKT packet
445 offset = dissect_mgcp(tvb, pinfo, tree);
450 * Dissect ASCII TPKT header
452 dissect_asciitpkt(tvb, pinfo, tree, mgcp_handle);
453 offset = tvb_length(tvb);
459 #define MAX_MGCP_MESSAGES_IN_PACKET 5
460 static mgcp_info_t pi_arr[MAX_MGCP_MESSAGES_IN_PACKET];
461 static int pi_current = 0;
462 static mgcp_info_t *mi;
464 /* Dissect an individual MGCP message */
465 static void dissect_mgcp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
466 proto_tree *mgcp_tree, proto_tree *ti)
468 /* Declare variables */
470 gint tvb_sectionend,tvb_sectionbegin, tvb_len, tvb_current_len;
472 const gchar *verb_name = "";
474 /* Initialise stat info for passing to tap */
476 if (pi_current == MAX_MGCP_MESSAGES_IN_PACKET)
478 /* Overwrite info in first struct if run out of space... */
481 mi = &pi_arr[pi_current];
484 mi->mgcp_type = MGCP_OTHERS;
487 mi->req_time.secs = 0;
488 mi->req_time.nsecs = 0;
489 mi->is_duplicate = FALSE;
490 mi->request_available = FALSE;
492 mi->endpointId = NULL;
493 mi->observedEvents = NULL;
495 mi->signalReq = NULL;
496 mi->hasDigitMap = FALSE;
498 /* Initialize variables */
500 tvb_sectionbegin = tvb_sectionend;
502 tvb_len = tvb_length(tvb);
503 tvb_current_len = tvb_len;
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 its cheap and its 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_current_len = tvb_len;
515 tvb_sectionend = tvb_sectionbegin;
516 sectionlen = tvb_find_line_end(tvb,0,-1,&tvb_sectionend,FALSE);
519 dissect_mgcp_firstline(tvb_new_subset(tvb, tvb_sectionbegin,
520 sectionlen,-1), pinfo,
523 tvb_sectionbegin = tvb_sectionend;
526 if (tvb_sectionbegin < tvb_len)
528 sectionlen = tvb_find_null_line(tvb, tvb_sectionbegin, -1,
532 dissect_mgcp_params(tvb_new_subset(tvb, tvb_sectionbegin, sectionlen, -1),
534 tvb_sectionbegin = tvb_sectionend;
538 /* Set the mgcp payload length correctly so we don't include any
540 sectionlen = tvb_sectionend;
541 proto_item_set_len(ti,sectionlen);
543 /* Display the raw text of the mgcp message if desired */
545 /* Do we want to display the raw text of our MGCP packet? */
546 if (global_mgcp_raw_text)
549 mgcp_raw_text_add(tvb, mgcp_tree);
552 /* Dissect sdp payload */
553 if (tvb_sectionend < tvb_len)
555 next_tvb = tvb_new_subset_remaining(tvb, tvb_sectionend);
556 call_dissector(sdp_handle, next_tvb, pinfo, tree);
563 * Add the raw text of the message to the dissect tree if appropriate
564 * preferences are specified.
566 static void mgcp_raw_text_add(tvbuff_t *tvb, proto_tree *tree)
568 gint tvb_linebegin,tvb_lineend,tvb_len,linelen;
571 tvb_len = tvb_length(tvb);
575 tvb_find_line_end(tvb,tvb_linebegin,-1,&tvb_lineend,FALSE);
576 linelen = tvb_lineend - tvb_linebegin;
577 proto_tree_add_text(tree, tvb, tvb_linebegin, linelen, "%s",
578 tvb_format_text(tvb, tvb_linebegin, linelen));
579 tvb_linebegin = tvb_lineend;
580 } while (tvb_lineend < tvb_len);
583 /* Discard and init any state we've saved */
584 static void mgcp_init_protocol(void)
586 if (mgcp_calls != NULL)
588 g_hash_table_destroy(mgcp_calls);
592 mgcp_calls = g_hash_table_new(mgcp_call_hash, mgcp_call_equal);
595 /* Register all the bits needed with the filtering engine */
596 void proto_register_mgcp(void)
598 static hf_register_info hf[] =
601 { "Request", "mgcp.req", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
602 "True if MGCP request", HFILL }},
604 { "Response", "mgcp.rsp", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
605 "TRUE if MGCP response", HFILL }},
606 { &hf_mgcp_req_frame,
607 { "Request Frame", "mgcp.reqframe", FT_FRAMENUM, BASE_NONE, NULL, 0,
609 { &hf_mgcp_rsp_frame,
610 { "Response Frame", "mgcp.rspframe", FT_FRAMENUM, BASE_NONE, NULL, 0,
613 { "Time from request", "mgcp.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0,
614 "Timedelta between Request and Response", HFILL }},
616 { "Verb", "mgcp.req.verb", FT_STRING, BASE_NONE, NULL, 0x0,
617 "Name of the verb", HFILL }},
618 { &hf_mgcp_req_endpoint,
619 { "Endpoint", "mgcp.req.endpoint", FT_STRING, BASE_NONE, NULL, 0x0,
620 "Endpoint referenced by the message", HFILL }},
622 { "Transaction ID", "mgcp.transid", FT_STRING, BASE_NONE, NULL, 0x0,
623 "Transaction ID of this message", HFILL }},
625 { "Version", "mgcp.version", FT_STRING, BASE_NONE, NULL, 0x0,
626 "MGCP Version", HFILL }},
627 { &hf_mgcp_rsp_rspcode,
628 { "Response Code", "mgcp.rsp.rspcode", FT_UINT32, BASE_DEC, VALS(mgcp_return_code_vals), 0x0,
630 { &hf_mgcp_rsp_rspstring,
631 { "Response String", "mgcp.rsp.rspstring", FT_STRING, BASE_NONE, NULL, 0x0,
634 { "Parameters", "mgcp.params", FT_NONE, BASE_NONE, NULL, 0x0,
635 "MGCP parameters", HFILL }},
636 { &hf_mgcp_param_rspack,
637 { "ResponseAck (K)", "mgcp.param.rspack", FT_STRING, BASE_NONE, NULL, 0x0,
638 "Response Ack", HFILL }},
639 { &hf_mgcp_param_bearerinfo,
640 { "BearerInformation (B)", "mgcp.param.bearerinfo", FT_STRING, BASE_NONE, NULL, 0x0,
641 "Bearer Information", HFILL }},
642 { &hf_mgcp_param_callid,
643 { "CallId (C)", "mgcp.param.callid", FT_STRING, BASE_NONE, NULL, 0x0,
645 { &hf_mgcp_param_connectionid,
646 {"ConnectionIdentifier (I)", "mgcp.param.connectionid", FT_STRING, BASE_NONE, NULL, 0x0,
647 "Connection Identifier", HFILL }},
648 { &hf_mgcp_param_secondconnectionid,
649 { "SecondConnectionID (I2)", "mgcp.param.secondconnectionid", FT_STRING, BASE_NONE, NULL, 0x0,
650 "Second Connection Identifier", HFILL }},
651 { &hf_mgcp_param_notifiedentity,
652 { "NotifiedEntity (N)", "mgcp.param.notifiedentity", FT_STRING, BASE_NONE, NULL, 0x0,
653 "Notified Entity", HFILL }},
654 { &hf_mgcp_param_requestid,
655 { "RequestIdentifier (X)", "mgcp.param.requestid", FT_STRING, BASE_NONE, NULL, 0x0,
656 "Request Identifier", HFILL }},
657 { &hf_mgcp_param_localconnoptions,
658 { "LocalConnectionOptions (L)", "mgcp.param.localconnectionoptions", FT_STRING, BASE_NONE, NULL, 0x0,
659 "Local Connection Options", HFILL }},
660 { &hf_mgcp_param_localconnoptions_p,
661 { "Packetization period (p)", "mgcp.param.localconnectionoptions.p", FT_UINT32, BASE_DEC, NULL, 0x0,
662 "Packetization period", HFILL }},
663 { &hf_mgcp_param_localconnoptions_a,
664 { "Codecs (a)", "mgcp.param.localconnectionoptions.a", FT_STRING, BASE_NONE, NULL, 0x0,
666 { &hf_mgcp_param_localconnoptions_s,
667 { "Silence Suppression (s)", "mgcp.param.localconnectionoptions.s", FT_STRING, BASE_NONE, NULL, 0x0,
668 "Silence Suppression", HFILL }},
669 { &hf_mgcp_param_localconnoptions_e,
670 { "Echo Cancellation (e)", "mgcp.param.localconnectionoptions.e", FT_STRING, BASE_NONE, NULL, 0x0,
671 "Echo Cancellation", HFILL }},
672 { &hf_mgcp_param_localconnoptions_scrtp,
673 { "RTP ciphersuite (sc-rtp)", "mgcp.param.localconnectionoptions.scrtp", FT_STRING, BASE_NONE, NULL, 0x0,
674 "RTP ciphersuite", HFILL }},
675 { &hf_mgcp_param_localconnoptions_scrtcp,
676 { "RTCP ciphersuite (sc-rtcp)", "mgcp.param.localconnectionoptions.scrtcp", FT_STRING, BASE_NONE, NULL, 0x0,
677 "RTCP ciphersuite", HFILL }},
678 { &hf_mgcp_param_localconnoptions_b,
679 { "Bandwidth (b)", "mgcp.param.localconnectionoptions.b", FT_STRING, BASE_NONE, NULL, 0x0,
680 "Bandwidth", HFILL }},
681 { &hf_mgcp_param_localconnoptions_esccd,
682 { "Content Destination (es-ccd)", "mgcp.param.localconnectionoptions.esccd", FT_STRING, BASE_NONE, NULL, 0x0,
683 "Content Destination", HFILL }},
684 { &hf_mgcp_param_localconnoptions_escci,
685 { "Content Identifier (es-cci)", "mgcp.param.localconnectionoptions.escci", FT_STRING, BASE_NONE, NULL, 0x0,
686 "Content Identifier", HFILL }},
687 { &hf_mgcp_param_localconnoptions_dqgi,
688 { "D-QoS GateID (dq-gi)", "mgcp.param.localconnectionoptions.dqgi", FT_STRING, BASE_NONE, NULL, 0x0,
689 "D-QoS GateID", HFILL }},
690 { &hf_mgcp_param_localconnoptions_dqrd,
691 { "D-QoS Reserve Destination (dq-rd)", "mgcp.param.localconnectionoptions.dqrd", FT_STRING, BASE_NONE, NULL, 0x0,
692 "D-QoS Reserve Destination", HFILL }},
693 { &hf_mgcp_param_localconnoptions_dqri,
694 { "D-QoS Resource ID (dq-ri)", "mgcp.param.localconnectionoptions.dqri", FT_STRING, BASE_NONE, NULL, 0x0,
695 "D-QoS Resource ID", HFILL }},
696 { &hf_mgcp_param_localconnoptions_dqrr,
697 { "D-QoS Resource Reservation (dq-rr)", "mgcp.param.localconnectionoptions.dqrr", FT_STRING, BASE_NONE, NULL, 0x0,
698 "D-QoS Resource Reservation", HFILL }},
699 { &hf_mgcp_param_localconnoptions_k,
700 { "Encryption Key (k)", "mgcp.param.localconnectionoptions.k", FT_STRING, BASE_NONE, NULL, 0x0,
701 "Encryption Key", HFILL }},
702 { &hf_mgcp_param_localconnoptions_gc,
703 { "Gain Control (gc)", "mgcp.param.localconnectionoptions.gc", FT_UINT32, BASE_DEC, NULL, 0x0,
704 "Gain Control", HFILL }},
705 { &hf_mgcp_param_localconnoptions_fmtp,
706 { "Media Format (fmtp)", "mgcp.param.localconnectionoptions.fmtp", FT_STRING, BASE_NONE, NULL, 0x0,
707 "Media Format", HFILL }},
708 { &hf_mgcp_param_localconnoptions_nt,
709 { "Network Type (nt)", "mgcp.param.localconnectionoptions.nt", FT_STRING, BASE_NONE, NULL, 0x0,
710 "Network Type", HFILL }},
711 { &hf_mgcp_param_localconnoptions_ofmtp,
712 { "Optional Media Format (o-fmtp)", "mgcp.param.localconnectionoptions.ofmtp", FT_STRING, BASE_NONE, NULL, 0x0,
713 "Optional Media Format", HFILL }},
714 { &hf_mgcp_param_localconnoptions_r,
715 { "Resource Reservation (r)", "mgcp.param.localconnectionoptions.r", FT_STRING, BASE_NONE, NULL, 0x0,
716 "Resource Reservation", HFILL }},
717 { &hf_mgcp_param_localconnoptions_t,
718 { "Type of Service (r)", "mgcp.param.localconnectionoptions.t", FT_STRING, BASE_NONE, NULL, 0x0,
719 "Type of Service", HFILL }},
720 { &hf_mgcp_param_localconnoptions_rcnf,
721 { "Reservation Confirmation (r-cnf)", "mgcp.param.localconnectionoptions.rcnf", FT_STRING, BASE_NONE, NULL, 0x0,
722 "Reservation Confirmation", HFILL }},
723 { &hf_mgcp_param_localconnoptions_rdir,
724 { "Reservation Direction (r-dir)", "mgcp.param.localconnectionoptions.rdir", FT_STRING, BASE_NONE, NULL, 0x0,
725 "Reservation Direction", HFILL }},
726 { &hf_mgcp_param_localconnoptions_rsh,
727 { "Resource Sharing (r-sh)", "mgcp.param.localconnectionoptions.rsh", FT_STRING, BASE_NONE, NULL, 0x0,
728 "Resource Sharing", HFILL }},
729 { &hf_mgcp_param_connectionmode,
730 { "ConnectionMode (M)", "mgcp.param.connectionmode", FT_STRING, BASE_NONE, NULL, 0x0,
731 "Connection Mode", HFILL }},
732 { &hf_mgcp_param_reqevents,
733 { "RequestedEvents (R)", "mgcp.param.reqevents", FT_STRING, BASE_NONE, NULL, 0x0,
734 "Requested Events", HFILL }},
735 { &hf_mgcp_param_signalreq,
736 { "SignalRequests (S)", "mgcp.param.signalreq", FT_STRING, BASE_NONE, NULL, 0x0,
737 "Signal Request", HFILL }},
738 { &hf_mgcp_param_restartmethod,
739 { "RestartMethod (RM)", "mgcp.param.restartmethod", FT_STRING, BASE_NONE, NULL, 0x0,
740 "Restart Method", HFILL }},
741 { &hf_mgcp_param_restartdelay,
742 { "RestartDelay (RD)", "mgcp.param.restartdelay", FT_STRING, BASE_NONE, NULL, 0x0,
743 "Restart Delay", HFILL }},
744 { &hf_mgcp_param_digitmap,
745 { "DigitMap (D)", "mgcp.param.digitmap", FT_STRING, BASE_NONE, NULL, 0x0,
746 "Digit Map", HFILL }},
747 { &hf_mgcp_param_observedevent,
748 { "ObservedEvents (O)", "mgcp.param.observedevents", FT_STRING, BASE_NONE, NULL, 0x0,
749 "Observed Events", HFILL }},
750 { &hf_mgcp_param_connectionparam,
751 { "ConnectionParameters (P)", "mgcp.param.connectionparam", FT_STRING, BASE_NONE, NULL, 0x0,
752 "Connection Parameters", HFILL }},
753 { &hf_mgcp_param_connectionparam_ps,
754 { "Packets sent (PS)", "mgcp.param.connectionparam.ps", FT_UINT32, BASE_DEC, NULL, 0x0,
755 "Packets sent (P:PS)", HFILL }},
756 { &hf_mgcp_param_connectionparam_os,
757 { "Octets sent (OS)", "mgcp.param.connectionparam.os", FT_UINT32, BASE_DEC, NULL, 0x0,
758 "Octets sent (P:OS)", HFILL }},
759 { &hf_mgcp_param_connectionparam_pr,
760 { "Packets received (PR)", "mgcp.param.connectionparam.pr", FT_UINT32, BASE_DEC, NULL, 0x0,
761 "Packets received (P:PR)", HFILL }},
762 { &hf_mgcp_param_connectionparam_or,
763 { "Octets received (OR)", "mgcp.param.connectionparam.or", FT_UINT32, BASE_DEC, NULL, 0x0,
764 "Octets received (P:OR)", HFILL }},
765 { &hf_mgcp_param_connectionparam_pl,
766 { "Packets lost (PL)", "mgcp.param.connectionparam.pl", FT_UINT32, BASE_DEC, NULL, 0x0,
767 "Packets lost (P:PL)", HFILL }},
768 { &hf_mgcp_param_connectionparam_ji,
769 { "Jitter (JI)", "mgcp.param.connectionparam.ji", FT_UINT32, BASE_DEC, NULL, 0x0,
770 "Average inter-packet arrival jitter in milliseconds (P:JI)", HFILL }},
771 { &hf_mgcp_param_connectionparam_la,
772 { "Latency (LA)", "mgcp.param.connectionparam.la", FT_UINT32, BASE_DEC, NULL, 0x0,
773 "Average latency in milliseconds (P:LA)", HFILL }},
774 { &hf_mgcp_param_connectionparam_pcrps,
775 { "Remote Packets sent (PC/RPS)", "mgcp.param.connectionparam.pcrps", FT_UINT32, BASE_DEC, NULL, 0x0,
776 "Remote Packets sent (P:PC/RPS)", HFILL }},
777 { &hf_mgcp_param_connectionparam_pcros,
778 { "Remote Octets sent (PC/ROS)", "mgcp.param.connectionparam.pcros", FT_UINT32, BASE_DEC, NULL, 0x0,
779 "Remote Octets sent (P:PC/ROS)", HFILL }},
780 { &hf_mgcp_param_connectionparam_pcrpl,
781 { "Remote Packets lost (PC/RPL)", "mgcp.param.connectionparam.pcrpl", FT_UINT32, BASE_DEC, NULL, 0x0,
782 "Remote Packets lost (P:PC/RPL)", HFILL }},
783 { &hf_mgcp_param_connectionparam_pcrji,
784 { "Remote Jitter (PC/RJI)", "mgcp.param.connectionparam.pcrji", FT_UINT32, BASE_DEC, NULL, 0x0,
785 "Remote Jitter (P:PC/RJI)", HFILL }},
786 { &hf_mgcp_param_connectionparam_x,
787 { "Vendor Extension", "mgcp.param.connectionparam.x", FT_STRING, BASE_NONE, NULL, 0x0,
788 "Vendor Extension (P:X-*)", HFILL }},
789 { &hf_mgcp_param_reasoncode,
790 { "ReasonCode (E)", "mgcp.param.reasoncode", FT_STRING, BASE_NONE, NULL, 0x0,
791 "Reason Code", HFILL }},
792 { &hf_mgcp_param_eventstates,
793 { "EventStates (ES)", "mgcp.param.eventstates", FT_STRING, BASE_NONE, NULL, 0x0,
794 "Event States", HFILL }},
795 { &hf_mgcp_param_specificendpoint,
796 { "SpecificEndpointID (Z)", "mgcp.param.specificendpointid", FT_STRING, BASE_NONE, NULL, 0x0,
797 "Specific Endpoint ID", HFILL }},
798 { &hf_mgcp_param_secondendpointid,
799 { "SecondEndpointID (Z2)", "mgcp.param.secondendpointid", FT_STRING, BASE_NONE, NULL, 0x0,
800 "Second Endpoint ID", HFILL }},
801 { &hf_mgcp_param_reqinfo,
802 { "RequestedInfo (F)", "mgcp.param.reqinfo", FT_STRING, BASE_NONE, NULL, 0x0,
803 "Requested Info", HFILL }},
804 { &hf_mgcp_param_quarantinehandling,
805 { "QuarantineHandling (Q)", "mgcp.param.quarantinehandling", FT_STRING, BASE_NONE, NULL, 0x0,
806 "Quarantine Handling", HFILL }},
807 { &hf_mgcp_param_detectedevents,
808 { "DetectedEvents (T)", "mgcp.param.detectedevents", FT_STRING, BASE_NONE, NULL, 0x0,
809 "Detected Events", HFILL }},
810 { &hf_mgcp_param_capabilities,
811 { "Capabilities (A)", "mgcp.param.capabilities", FT_STRING, BASE_NONE, NULL, 0x0,
812 "Capabilities", HFILL }},
813 { &hf_mgcp_param_maxmgcpdatagram,
814 {"MaxMGCPDatagram (MD)", "mgcp.param.maxmgcpdatagram", FT_STRING, BASE_NONE, NULL, 0x0,
815 "Maximum MGCP Datagram size", HFILL }},
816 { &hf_mgcp_param_packagelist,
817 {"PackageList (PL)", "mgcp.param.packagelist", FT_STRING, BASE_NONE, NULL, 0x0,
818 "Package List", HFILL }},
819 { &hf_mgcp_param_extension,
820 { "Extension Parameter (non-critical)", "mgcp.param.extension", FT_STRING, BASE_NONE, NULL, 0x0,
821 "Extension Parameter", HFILL }},
822 { &hf_mgcp_param_extension_critical,
823 { "Extension Parameter (critical)", "mgcp.param.extensioncritical", FT_STRING, BASE_NONE, NULL, 0x0,
824 "Critical Extension Parameter", HFILL }},
825 { &hf_mgcp_param_invalid,
826 { "Invalid Parameter", "mgcp.param.invalid", FT_STRING, BASE_NONE, NULL, 0x0,
828 { &hf_mgcp_messagecount,
829 { "MGCP Message Count", "mgcp.messagecount", FT_UINT32, BASE_DEC, NULL, 0x0,
830 "Number of MGCP message in a packet", HFILL }},
832 { "Duplicate Message", "mgcp.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
835 { "Duplicate Request", "mgcp.req.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
837 { &hf_mgcp_req_dup_frame,
838 { "Original Request Frame", "mgcp.req.dup.frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
839 "Frame containing original request", HFILL }},
841 { "Duplicate Response", "mgcp.rsp.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
843 { &hf_mgcp_rsp_dup_frame,
844 { "Original Response Frame", "mgcp.rsp.dup.frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
845 "Frame containing original response", HFILL }},
852 &ett_mgcp_param_connectionparam,
853 &ett_mgcp_param_localconnectionoptions
856 module_t *mgcp_module;
858 /* Register protocol */
859 proto_mgcp = proto_register_protocol("Media Gateway Control Protocol", "MGCP", "mgcp");
860 proto_register_field_array(proto_mgcp, hf, array_length(hf));
861 proto_register_subtree_array(ett, array_length(ett));
862 register_init_routine(&mgcp_init_protocol);
864 new_register_dissector("mgcp", dissect_mgcp, proto_mgcp);
866 /* Register our configuration options */
867 mgcp_module = prefs_register_protocol(proto_mgcp, proto_reg_handoff_mgcp);
869 prefs_register_uint_preference(mgcp_module, "tcp.gateway_port",
870 "MGCP Gateway TCP Port",
871 "Set the UDP port for gateway messages "
872 "(if other than the default of 2427)",
873 10, &global_mgcp_gateway_tcp_port);
875 prefs_register_uint_preference(mgcp_module, "udp.gateway_port",
876 "MGCP Gateway UDP Port",
877 "Set the TCP port for gateway messages "
878 "(if other than the default of 2427)",
879 10, &global_mgcp_gateway_udp_port);
881 prefs_register_uint_preference(mgcp_module, "tcp.callagent_port",
882 "MGCP Callagent TCP Port",
883 "Set the TCP port for callagent messages "
884 "(if other than the default of 2727)",
885 10, &global_mgcp_callagent_tcp_port);
887 prefs_register_uint_preference(mgcp_module, "udp.callagent_port",
888 "MGCP Callagent UDP Port",
889 "Set the UDP port for callagent messages "
890 "(if other than the default of 2727)",
891 10, &global_mgcp_callagent_udp_port);
894 prefs_register_bool_preference(mgcp_module, "display_raw_text",
895 "Display raw text for MGCP message",
896 "Specifies that the raw text of the "
897 "MGCP message should be displayed "
898 "instead of (or in addition to) the "
900 &global_mgcp_raw_text);
902 prefs_register_obsolete_preference(mgcp_module, "display_dissect_tree");
904 prefs_register_bool_preference(mgcp_module, "display_mgcp_message_count",
905 "Display the number of MGCP messages",
906 "Display the number of MGCP messages "
907 "found in a packet in the protocol column.",
908 &global_mgcp_message_count);
910 mgcp_tap = register_tap("mgcp");
913 /* The registration hand-off routine */
914 void proto_reg_handoff_mgcp(void)
916 static gboolean mgcp_prefs_initialized = FALSE;
917 static dissector_handle_t mgcp_tpkt_handle;
919 * Variables to allow for proper deletion of dissector registration when
920 * the user changes port from the gui.
922 static guint gateway_tcp_port;
923 static guint gateway_udp_port;
924 static guint callagent_tcp_port;
925 static guint callagent_udp_port;
927 if (!mgcp_prefs_initialized)
929 /* Get a handle for the SDP dissector. */
930 sdp_handle = find_dissector("sdp");
931 mgcp_handle = new_create_dissector_handle(dissect_mgcp, proto_mgcp);
932 mgcp_tpkt_handle = new_create_dissector_handle(dissect_tpkt_mgcp, proto_mgcp);
933 mgcp_prefs_initialized = TRUE;
937 dissector_delete_uint("tcp.port", gateway_tcp_port, mgcp_tpkt_handle);
938 dissector_delete_uint("udp.port", gateway_udp_port, mgcp_handle);
939 dissector_delete_uint("tcp.port", callagent_tcp_port, mgcp_tpkt_handle);
940 dissector_delete_uint("udp.port", callagent_udp_port, mgcp_handle);
943 /* Set our port number for future use */
944 gateway_tcp_port = global_mgcp_gateway_tcp_port;
945 gateway_udp_port = global_mgcp_gateway_udp_port;
947 callagent_tcp_port = global_mgcp_callagent_tcp_port;
948 callagent_udp_port = global_mgcp_callagent_udp_port;
950 dissector_add_uint("tcp.port", global_mgcp_gateway_tcp_port, mgcp_tpkt_handle);
951 dissector_add_uint("udp.port", global_mgcp_gateway_udp_port, mgcp_handle);
952 dissector_add_uint("tcp.port", global_mgcp_callagent_tcp_port, mgcp_tpkt_handle);
953 dissector_add_uint("udp.port", global_mgcp_callagent_udp_port, mgcp_handle);
957 * is_mgcp_verb - A function for determining whether there is a
958 * MGCP verb at offset in tvb
961 * tvb - The tvbuff in which we are looking for an MGCP verb
962 * offset - The offset in tvb at which we are looking for a MGCP verb
963 * maxlength - The maximum distance from offset we may look for the
964 * characters that make up a MGCP verb.
965 * verb_name - The name for the verb code found (output)
967 * Return: TRUE if there is an MGCP verb at offset in tvb, otherwise FALSE
969 static gboolean is_mgcp_verb(tvbuff_t *tvb, gint offset, gint maxlength, const gchar **verb_name)
971 int returnvalue = FALSE;
974 /* Read the string into 'word' and see if it looks like the start of a verb */
975 if ((maxlength >= 4) && tvb_get_nstringz0(tvb, offset, sizeof(word), word))
977 if (((g_ascii_strncasecmp(word, "EPCF", 4) == 0) && (*verb_name = "EndpointConfiguration")) ||
978 ((g_ascii_strncasecmp(word, "CRCX", 4) == 0) && (*verb_name = "CreateConnection")) ||
979 ((g_ascii_strncasecmp(word, "MDCX", 4) == 0) && (*verb_name = "ModifyConnection")) ||
980 ((g_ascii_strncasecmp(word, "DLCX", 4) == 0) && (*verb_name = "DeleteConnection")) ||
981 ((g_ascii_strncasecmp(word, "RQNT", 4) == 0) && (*verb_name = "NotificationRequest")) ||
982 ((g_ascii_strncasecmp(word, "NTFY", 4) == 0) && (*verb_name = "Notify")) ||
983 ((g_ascii_strncasecmp(word, "AUEP", 4) == 0) && (*verb_name = "AuditEndpoint")) ||
984 ((g_ascii_strncasecmp(word, "AUCX", 4) == 0) && (*verb_name = "AuditConnection")) ||
985 ((g_ascii_strncasecmp(word, "RSIP", 4) == 0) && (*verb_name = "RestartInProgress")) ||
986 ((g_ascii_strncasecmp(word, "MESG", 4) == 0) && (*verb_name = "Message")) ||
987 (word[0] == 'X' && is_rfc2234_alpha(word[1]) && is_rfc2234_alpha(word[2]) &&
988 is_rfc2234_alpha(word[3]) && (*verb_name = "*Experimental*")))
994 /* May be whitespace after verb code - anything else is an error.. */
995 if (returnvalue && maxlength >= 5)
997 char next = tvb_get_guint8(tvb,4);
998 if ((next != ' ') && (next != '\t'))
1000 returnvalue = FALSE;
1008 * is_mgcp_rspcode - A function for determining whether something which
1009 * looks roughly like a MGCP response code (3-digit number)
1010 * is at 'offset' in tvb
1013 * tvb - The tvbuff in which we are looking for an MGCP response code
1014 * offset - The offset in tvb at which we are looking for a MGCP response code
1015 * maxlength - The maximum distance from offset we may look for the
1016 * characters that make up a MGCP response code.
1018 * Return: TRUE if there is an MGCP response code at offset in tvb,
1021 static gboolean is_mgcp_rspcode(tvbuff_t *tvb, gint offset, gint maxlength)
1023 int returnvalue = FALSE;
1026 /* Do 1st 3 characters look like digits? */
1029 tvb_get_nstringz0(tvb, offset, sizeof(word), word);
1030 if (isdigit(word[0]) && isdigit(word[1]) && isdigit(word[2]))
1036 /* Maybe some white space after the 3rd digit - anything else is an error */
1037 if (returnvalue && maxlength >= 4)
1039 char next = tvb_get_guint8(tvb, 3);
1040 if ((next != ' ') && (next != '\t'))
1042 returnvalue = FALSE;
1050 * is_rfc2234_alpha - Indicates whether the character c is an alphabetical
1051 * character. This function is used instead of
1052 * isalpha because isalpha may deviate from the rfc2234
1053 * definition of ALPHA in some locales.
1056 * c - The character being checked for being an alphabetical character.
1058 * Return: TRUE if c is an upper or lower case alphabetical character,
1061 static gboolean is_rfc2234_alpha(guint8 c)
1063 return ((c <= 'Z' && c >= 'A' ) || (c <= 'z' && c >= 'a'));
1068 * tvb_parse_param - Parse the MGCP param into a type and a value.
1071 * tvb - The tvbuff containing the MGCP param we are to parse.
1072 * offset - The offset in tvb at which we will begin looking for a
1073 * MGCP parameter to parse.
1074 * len - The maximum distance from offset in tvb that we can look for
1075 * an MGCP parameter to parse.
1076 * hf - The place to write a pointer to the integer representing the
1077 * header field associated with the MGCP parameter parsed.
1079 * Returns: The offset in tvb where the value of the MGCP parameter
1082 static gint tvb_parse_param(tvbuff_t* tvb, gint offset, gint len, int** hf)
1084 gint returnvalue = -1, tvb_current_offset,counter;
1085 guint8 tempchar, plus_minus;
1088 tvb_current_offset = offset;
1094 tempchar = tvb_get_guint8(tvb,tvb_current_offset);
1099 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1101 *hf = &hf_mgcp_param_invalid;
1104 *hf = &hf_mgcp_param_rspack;
1107 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1109 *hf = &hf_mgcp_param_invalid;
1112 *hf = &hf_mgcp_param_bearerinfo;
1115 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1117 *hf = &hf_mgcp_param_invalid;
1120 *hf = &hf_mgcp_param_callid;
1123 tvb_current_offset++;
1124 if (len > (tvb_current_offset - offset) &&
1125 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1127 *hf = &hf_mgcp_param_connectionid;
1128 tvb_current_offset--;
1131 if (tempchar == '2')
1133 *hf = &hf_mgcp_param_secondconnectionid;
1137 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1139 *hf = &hf_mgcp_param_invalid;
1142 *hf = &hf_mgcp_param_notifiedentity;
1146 tvb_current_offset++;
1148 /* X: is RequestIdentifier */
1149 if (len > (tvb_current_offset - offset) &&
1150 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1152 *hf = &hf_mgcp_param_requestid;
1153 tvb_current_offset--;
1156 /* X+...: or X-....: are vendor extension parameters */
1158 if (len > (tvb_current_offset - offset) &&
1159 ((plus_minus = tvb_get_guint8(tvb,tvb_current_offset)) == '-' ||
1160 (plus_minus == '+')))
1162 /* Move past + or - */
1163 tvb_current_offset++;
1165 /* Keep going, through possible vendor param name */
1167 ((len > (counter + tvb_current_offset-offset)) &&
1168 (is_rfc2234_alpha(tempchar = tvb_get_guint8(tvb, tvb_current_offset+counter)) ||
1169 isdigit(tempchar))) ;
1172 if (tempchar == ':')
1174 /* Looks like a valid vendor param name */
1175 tvb_current_offset += counter;
1179 *hf = &hf_mgcp_param_extension_critical;
1182 *hf = &hf_mgcp_param_extension;
1189 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1191 *hf = &hf_mgcp_param_invalid;
1194 *hf = &hf_mgcp_param_localconnoptions;
1197 tvb_current_offset++;
1198 if (len > (tvb_current_offset - offset) &&
1199 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1201 *hf = &hf_mgcp_param_connectionmode;
1202 tvb_current_offset--;
1205 if (tempchar == 'D')
1207 *hf = &hf_mgcp_param_maxmgcpdatagram;
1211 tvb_current_offset++;
1212 if (len > (tvb_current_offset - offset) &&
1213 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1215 *hf = &hf_mgcp_param_reqevents;
1216 tvb_current_offset--;
1219 if ( tempchar == 'M')
1221 *hf = &hf_mgcp_param_restartmethod;
1224 if (tempchar == 'D')
1226 *hf = &hf_mgcp_param_restartdelay;
1230 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1232 *hf = &hf_mgcp_param_invalid;
1235 *hf = &hf_mgcp_param_signalreq;
1236 buf = &(mi->signalReq);
1239 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1241 *hf = &hf_mgcp_param_invalid;
1244 *hf = &hf_mgcp_param_digitmap;
1245 mi->hasDigitMap = TRUE;
1248 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1250 *hf = &hf_mgcp_param_invalid;
1253 *hf = &hf_mgcp_param_observedevent;
1254 buf = &(mi->observedEvents);
1257 tvb_current_offset++;
1258 if (len > (tvb_current_offset - offset) &&
1259 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1261 *hf = &hf_mgcp_param_connectionparam;
1262 tvb_current_offset--;
1265 if ( tempchar == 'L')
1267 *hf = &hf_mgcp_param_packagelist;
1271 tvb_current_offset++;
1272 if (len > (tvb_current_offset - offset) &&
1273 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1275 *hf = &hf_mgcp_param_reasoncode;
1276 tvb_current_offset--;
1279 if ( tempchar == 'S')
1281 *hf = &hf_mgcp_param_eventstates;
1285 tvb_current_offset++;
1286 if (len > (tvb_current_offset - offset) &&
1287 (tempchar = tvb_get_guint8(tvb,tvb_current_offset)) == ':')
1289 *hf = &hf_mgcp_param_specificendpoint;
1290 tvb_current_offset--;
1293 if (tempchar == '2')
1295 *hf = &hf_mgcp_param_secondendpointid;
1299 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1301 *hf = &hf_mgcp_param_invalid;
1304 *hf = &hf_mgcp_param_reqinfo;
1307 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1309 *hf = &hf_mgcp_param_invalid;
1312 *hf = &hf_mgcp_param_quarantinehandling;
1315 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1317 *hf = &hf_mgcp_param_invalid;
1320 *hf = &hf_mgcp_param_detectedevents;
1323 if (tvb_get_guint8(tvb,tvb_current_offset+1) != ':')
1325 *hf = &hf_mgcp_param_invalid;
1328 *hf = &hf_mgcp_param_capabilities;
1332 *hf = &hf_mgcp_param_invalid;
1336 /* Move to (hopefully) the colon */
1337 tvb_current_offset++;
1339 /* Add a recognised parameter type if we have one */
1340 if (*hf != NULL && len > (tvb_current_offset - offset) &&
1341 tvb_get_guint8(tvb,tvb_current_offset) == ':')
1343 tvb_current_offset++;
1344 tvb_current_offset = tvb_skip_wsp(tvb,tvb_current_offset, (len - tvb_current_offset + offset));
1345 returnvalue = tvb_current_offset;
1347 /* set the observedEvents or signalReq used in Voip Calls analysis */
1349 *buf = tvb_get_ephemeral_string(tvb, tvb_current_offset, (len - tvb_current_offset + offset));
1355 /* Was an empty line */
1356 *hf = &hf_mgcp_param_invalid;
1359 /* For these types, show the whole line */
1360 if ((*hf == &hf_mgcp_param_invalid) ||
1361 (*hf == &hf_mgcp_param_extension) || (*hf == &hf_mgcp_param_extension_critical))
1363 returnvalue = offset;
1371 * dissect_mgcp_firstline - Dissects the firstline of an MGCP message.
1372 * Adds the appropriate headers fields to
1373 * tree for the dissection of the first line
1374 * of an MGCP message.
1377 * tvb - The tvb containing the first line of an MGCP message. This
1378 * tvb is presumed to ONLY contain the first line of the MGCP
1380 * pinfo - The packet info for the packet. This is not really used
1381 * by this function but is passed through so as to retain the
1382 * style of a dissector.
1383 * tree - The tree from which to hang the structured information parsed
1384 * from the first line of the MGCP message.
1386 static void dissect_mgcp_firstline(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1388 gint tvb_current_offset,tvb_previous_offset,tvb_len,tvb_current_len;
1389 gint tokennum, tokenlen;
1390 proto_item* hidden_item;
1391 char *transid = NULL;
1393 char *endpointId = NULL;
1394 mgcp_type_t mgcp_type = MGCP_OTHERS;
1395 conversation_t* conversation;
1396 mgcp_call_info_key mgcp_call_key;
1397 mgcp_call_info_key *new_mgcp_call_key = NULL;
1398 mgcp_call_t *mgcp_call = NULL;
1401 const gchar *verb_description = "";
1402 char code_with_verb[64] = ""; /* To fit "<4-letter-code> (<longest-verb>)" */
1404 static address null_address = { AT_NONE, 0, NULL };
1405 tvb_previous_offset = 0;
1406 tvb_len = tvb_length(tvb);
1407 tvb_current_len = tvb_len;
1408 tvb_current_offset = tvb_previous_offset;
1409 mi->is_duplicate = FALSE;
1410 mi->request_available = FALSE;
1418 tvb_current_len = tvb_length_remaining(tvb,tvb_previous_offset);
1419 tvb_current_offset = tvb_find_guint8(tvb, tvb_previous_offset, tvb_current_len, ' ');
1420 if (tvb_current_offset == -1)
1422 tvb_current_offset = tvb_len;
1423 tokenlen = tvb_current_len;
1427 tokenlen = tvb_current_offset - tvb_previous_offset;
1432 THROW(ReportedBoundsError);
1433 code = tvb_format_text(tvb,tvb_previous_offset,tokenlen);
1434 g_strlcpy(mi->code,code,5);
1435 if (is_mgcp_verb(tvb,tvb_previous_offset,tvb_current_len,&verb_description))
1437 mgcp_type = MGCP_REQUEST;
1438 if (verb_description != NULL)
1440 /* Can show verb along with code if known */
1441 g_snprintf(code_with_verb, 64, "%s (%s)", code, verb_description);
1444 proto_tree_add_string_format(tree, hf_mgcp_req_verb, tvb,
1445 tvb_previous_offset, tokenlen,
1447 strlen(code_with_verb) ? code_with_verb : code);
1450 if (is_mgcp_rspcode(tvb,tvb_previous_offset,tvb_current_len))
1452 mgcp_type = MGCP_RESPONSE;
1453 rspcode = atoi(code);
1454 mi->rspcode = rspcode;
1455 proto_tree_add_uint(tree,hf_mgcp_rsp_rspcode, tvb,
1456 tvb_previous_offset, tokenlen, rspcode);
1465 transid = tvb_format_text(tvb,tvb_previous_offset,tokenlen);
1466 /* XXX - what if this isn't a valid text string? */
1467 mi->transid = atol(transid);
1468 proto_tree_add_string(tree, hf_mgcp_transid, tvb,
1469 tvb_previous_offset, tokenlen, transid);
1473 if (mgcp_type == MGCP_REQUEST)
1475 endpointId = tvb_format_text(tvb, tvb_previous_offset,tokenlen);
1476 mi->endpointId = ep_strdup(endpointId);
1477 proto_tree_add_string(tree,hf_mgcp_req_endpoint, tvb,
1478 tvb_previous_offset, tokenlen, endpointId);
1481 if (mgcp_type == MGCP_RESPONSE)
1483 if (tvb_current_offset < tvb_len)
1485 tokenlen = tvb_find_line_end(tvb, tvb_previous_offset,
1486 -1, &tvb_current_offset, FALSE);
1490 tokenlen = tvb_current_len;
1492 proto_tree_add_string(tree, hf_mgcp_rsp_rspstring, tvb,
1493 tvb_previous_offset, tokenlen,
1494 tvb_format_text(tvb, tvb_previous_offset,
1500 if ((tokennum == 3 && mgcp_type == MGCP_REQUEST))
1502 if (tvb_current_offset < tvb_len )
1504 tokenlen = tvb_find_line_end(tvb, tvb_previous_offset,
1505 -1, &tvb_current_offset,FALSE);
1509 tokenlen = tvb_current_len;
1511 proto_tree_add_string(tree,hf_mgcp_version, tvb,
1512 tvb_previous_offset, tokenlen,
1513 tvb_format_text(tvb,tvb_previous_offset,
1517 if (tvb_current_offset < tvb_len)
1519 tvb_previous_offset = tvb_skip_wsp(tvb, tvb_current_offset,
1523 } while (tvb_current_offset < tvb_len && tvb_previous_offset < tvb_len && tokennum <= 3);
1528 hidden_item = proto_tree_add_boolean(tree, hf_mgcp_rsp, tvb, 0, 0, TRUE);
1529 PROTO_ITEM_SET_HIDDEN(hidden_item);
1530 /* Check for MGCP response. A response must match a call that
1531 we've seen, and the response must be sent to the same
1532 port and address that the call came from, and must
1533 come from the port to which the call was sent.
1535 If the transport is connection-oriented (we check, for
1536 now, only for "pinfo->ptype" of PT_TCP), we take
1537 into account the address from which the call was sent
1538 and the address to which the call was sent, because
1539 the addresses of the two endpoints should be the same
1540 for all calls and replies.
1542 If the transport is connectionless, we don't worry
1543 about the address to which the call was sent and from
1544 which the reply was sent, because there's no
1545 guarantee that the reply will come from the address
1546 to which the call was sent. */
1547 if (pinfo->ptype == PT_TCP)
1549 conversation = find_conversation(pinfo->fd->num, &pinfo->src,
1550 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1551 pinfo->destport, 0);
1555 /* XXX - can we just use NO_ADDR_B? Unfortunately,
1556 * you currently still have to pass a non-null
1557 * pointer for the second address argument even
1560 conversation = find_conversation(pinfo->fd->num, &null_address,
1561 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1562 pinfo->destport, 0);
1564 if (conversation != NULL)
1566 /* Look only for matching request, if
1567 matching conversation is available. */
1568 mgcp_call_key.transid = mi->transid;
1569 mgcp_call_key.conversation = conversation;
1570 mgcp_call = g_hash_table_lookup(mgcp_calls, &mgcp_call_key);
1573 /* Indicate the frame to which this is a reply. */
1574 if (mgcp_call->req_num)
1577 mi->request_available = TRUE;
1578 mgcp_call->responded = TRUE;
1579 mi->req_num = mgcp_call->req_num;
1580 g_strlcpy(mi->code,mgcp_call->code,5);
1581 item = proto_tree_add_uint_format(tree, hf_mgcp_req_frame,
1582 tvb, 0, 0, mgcp_call->req_num,
1583 "This is a response to a request in frame %u",
1584 mgcp_call->req_num);
1585 PROTO_ITEM_SET_GENERATED(item);
1586 nstime_delta(&delta, &pinfo->fd->abs_ts, &mgcp_call->req_time);
1587 item = proto_tree_add_time(tree, hf_mgcp_time, tvb, 0, 0, &delta);
1588 PROTO_ITEM_SET_GENERATED(item);
1591 if (mgcp_call->rsp_num == 0)
1593 /* We have not yet seen a response to that call, so
1594 this must be the first response; remember its
1596 mgcp_call->rsp_num = pinfo->fd->num;
1600 /* We have seen a response to this call - but was it
1601 *this* response? (disregard provisional responses) */
1602 if ((mgcp_call->rsp_num != pinfo->fd->num) &&
1603 (mi->rspcode >= 200) &&
1604 (mi->rspcode == mgcp_call->rspcode))
1606 /* No, so it's a duplicate response. Mark it as such. */
1607 mi->is_duplicate = TRUE;
1608 col_append_fstr(pinfo->cinfo, COL_INFO,
1609 ", Duplicate Response %u",
1614 item = proto_tree_add_uint(tree, hf_mgcp_dup, tvb, 0,0, mi->transid);
1615 PROTO_ITEM_SET_HIDDEN(item);
1616 item = proto_tree_add_uint(tree, hf_mgcp_rsp_dup,
1617 tvb, 0, 0, mi->transid);
1618 PROTO_ITEM_SET_GENERATED(item);
1619 item = proto_tree_add_uint(tree, hf_mgcp_rsp_dup_frame,
1620 tvb, 0, 0, mgcp_call->rsp_num);
1621 PROTO_ITEM_SET_GENERATED(item);
1625 /* Now store the response code (after comparison above) */
1626 mgcp_call->rspcode = mi->rspcode;
1631 hidden_item = proto_tree_add_boolean(tree, hf_mgcp_req, tvb, 0, 0, TRUE);
1632 PROTO_ITEM_SET_HIDDEN(hidden_item);
1633 /* Keep track of the address and port whence the call came,
1634 * and the port to which the call is being sent, so that
1635 * we can match up calls with replies.
1637 * If the transport is connection-oriented (we check, for
1638 * now, only for "pinfo->ptype" of PT_TCP), we take
1639 * into account the address from which the call was sent
1640 * and the address to which the call was sent, because
1641 * the addresses of the two endpoints should be the same
1642 * for all calls and replies.
1644 * If the transport is connectionless, we don't worry
1645 * about the address to which the call was sent and from
1646 * which the reply was sent, because there's no
1647 * guarantee that the reply will come from the address
1648 * to which the call was sent.
1650 if (pinfo->ptype == PT_TCP)
1652 conversation = find_conversation(pinfo->fd->num, &pinfo->src,
1653 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1654 pinfo->destport, 0);
1659 * XXX - can we just use NO_ADDR_B? Unfortunately,
1660 * you currently still have to pass a non-null
1661 * pointer for the second address argument even
1664 conversation = find_conversation(pinfo->fd->num, &pinfo->src,
1665 &null_address, pinfo->ptype, pinfo->srcport,
1666 pinfo->destport, 0);
1668 if (conversation == NULL)
1670 /* It's not part of any conversation - create a new one. */
1671 if (pinfo->ptype == PT_TCP)
1673 conversation = conversation_new(pinfo->fd->num, &pinfo->src,
1674 &pinfo->dst, pinfo->ptype, pinfo->srcport,
1675 pinfo->destport, 0);
1679 conversation = conversation_new(pinfo->fd->num, &pinfo->src,
1680 &null_address, pinfo->ptype, pinfo->srcport,
1681 pinfo->destport, 0);
1685 /* Prepare the key data */
1686 mgcp_call_key.transid = mi->transid;
1687 mgcp_call_key.conversation = conversation;
1689 /* Look up the request */
1690 mgcp_call = g_hash_table_lookup(mgcp_calls, &mgcp_call_key);
1691 if (mgcp_call != NULL)
1693 /* We've seen a request with this TRANSID, with the same
1694 source and destination, before - but was it
1696 if (pinfo->fd->num != mgcp_call->req_num)
1698 /* No, so it's a duplicate request. Mark it as such. */
1699 mi->is_duplicate = TRUE;
1700 mi->req_num = mgcp_call->req_num;
1701 col_append_fstr(pinfo->cinfo, COL_INFO,
1702 ", Duplicate Request %u",
1707 item = proto_tree_add_uint(tree, hf_mgcp_dup, tvb, 0,0, mi->transid);
1708 PROTO_ITEM_SET_HIDDEN(item);
1709 item = proto_tree_add_uint(tree, hf_mgcp_req_dup, tvb, 0,0, mi->transid);
1710 PROTO_ITEM_SET_GENERATED(item);
1711 item = proto_tree_add_uint(tree, hf_mgcp_req_dup_frame, tvb, 0,0, mi->req_num);
1712 PROTO_ITEM_SET_GENERATED(item);
1718 /* Prepare the value data.
1719 "req_num" and "rsp_num" are frame numbers;
1720 frame numbers are 1-origin, so we use 0
1721 to mean "we don't yet know in which frame
1722 the reply for this call appears". */
1723 new_mgcp_call_key = se_alloc(sizeof(*new_mgcp_call_key));
1724 *new_mgcp_call_key = mgcp_call_key;
1725 mgcp_call = se_alloc(sizeof(*mgcp_call));
1726 mgcp_call->req_num = pinfo->fd->num;
1727 mgcp_call->rsp_num = 0;
1728 mgcp_call->transid = mi->transid;
1729 mgcp_call->responded = FALSE;
1730 mgcp_call->req_time=pinfo->fd->abs_ts;
1731 g_strlcpy(mgcp_call->code,mi->code,5);
1734 g_hash_table_insert(mgcp_calls, new_mgcp_call_key, mgcp_call);
1736 if (mgcp_call->rsp_num)
1738 proto_item* item = proto_tree_add_uint_format(tree, hf_mgcp_rsp_frame,
1739 tvb, 0, 0, mgcp_call->rsp_num,
1740 "The response to this request is in frame %u",
1741 mgcp_call->rsp_num);
1742 PROTO_ITEM_SET_GENERATED(item);
1749 mi->mgcp_type = mgcp_type;
1752 mi->req_time.secs=mgcp_call->req_time.secs;
1753 mi->req_time.nsecs=mgcp_call->req_time.nsecs;
1757 tap_queue_packet(mgcp_tap, pinfo, mi);
1761 * dissect_mgcp_params - Dissects the parameters of an MGCP message.
1762 * Adds the appropriate headers fields to
1763 * tree for the dissection of the parameters
1764 * of an MGCP message.
1767 * tvb - The tvb containing the parameters of an MGCP message. This
1768 * tvb is presumed to ONLY contain the part of the MGCP
1769 * message which contains the MGCP parameters.
1770 * tree - The tree from which to hang the structured information parsed
1771 * from the parameters of the MGCP message.
1773 static void dissect_mgcp_params(tvbuff_t *tvb, proto_tree *tree)
1775 int linelen, tokenlen, *my_param;
1776 gint tvb_lineend,tvb_current_len, tvb_linebegin,tvb_len,old_lineend;
1777 gint tvb_tokenbegin;
1778 proto_tree *mgcp_param_ti, *mgcp_param_tree;
1780 tvb_len = tvb_length(tvb);
1782 tvb_current_len = tvb_length_remaining(tvb,tvb_linebegin);
1783 tvb_lineend = tvb_linebegin;
1787 mgcp_param_ti = proto_tree_add_item(tree, hf_mgcp_params, tvb,
1788 tvb_linebegin, tvb_len, FALSE);
1789 proto_item_set_text(mgcp_param_ti, "Parameters");
1790 mgcp_param_tree = proto_item_add_subtree(mgcp_param_ti, ett_mgcp_param);
1792 /* Parse the parameters */
1793 while (tvb_lineend < tvb_len)
1795 old_lineend = tvb_lineend;
1796 linelen = tvb_find_line_end(tvb, tvb_linebegin, -1,&tvb_lineend,FALSE);
1797 tvb_tokenbegin = tvb_parse_param(tvb, tvb_linebegin, linelen, &my_param);
1801 if (*my_param == hf_mgcp_param_connectionparam)
1803 tokenlen = tvb_find_line_end(tvb,tvb_tokenbegin,-1,&tvb_lineend,FALSE);
1804 dissect_mgcp_connectionparams(mgcp_param_tree, tvb, tvb_linebegin,
1805 tvb_tokenbegin - tvb_linebegin, tokenlen);
1808 if (*my_param == hf_mgcp_param_localconnoptions)
1810 tokenlen = tvb_find_line_end(tvb,tvb_tokenbegin,-1,&tvb_lineend,FALSE);
1811 dissect_mgcp_localconnectionoptions(mgcp_param_tree, tvb, tvb_linebegin,
1812 tvb_tokenbegin - tvb_linebegin, tokenlen);
1816 tokenlen = tvb_find_line_end(tvb,tvb_tokenbegin,-1,&tvb_lineend,FALSE);
1817 proto_tree_add_string(mgcp_param_tree,*my_param, tvb,
1818 tvb_linebegin, linelen,
1819 tvb_format_text(tvb,tvb_tokenbegin, tokenlen));
1823 tvb_linebegin = tvb_lineend;
1824 /* Its a infinite loop if we didn't advance (or went backwards) */
1825 if (old_lineend >= tvb_lineend)
1827 THROW(ReportedBoundsError);
1833 /* Dissect the connection params */
1835 dissect_mgcp_connectionparams(proto_tree *parent_tree, tvbuff_t *tvb, gint offset, gint param_type_len, gint param_val_len)
1837 proto_tree *tree = parent_tree;
1838 proto_item *item = NULL;
1840 gchar *tokenline = NULL;
1841 gchar **tokens = NULL;
1842 gchar **typval = NULL;
1850 item = proto_tree_add_item(parent_tree, hf_mgcp_param_connectionparam, tvb, offset, param_type_len+param_val_len, FALSE);
1851 tree = proto_item_add_subtree(item, ett_mgcp_param_connectionparam);
1855 offset += param_type_len; /* skip the P: */
1856 tokenline = tvb_get_ephemeral_string(tvb, offset, param_val_len);
1858 /* Split into type=value pairs separated by comma */
1859 tokens = ep_strsplit(tokenline, ",", -1);
1861 for (i = 0; tokens[i] != NULL; i++)
1863 tokenlen = (int)strlen(tokens[i]);
1864 typval = ep_strsplit(tokens[i], "=", 2);
1865 if ((typval[0] != NULL) && (typval[1] != NULL))
1867 if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PS"))
1869 hf_uint = hf_mgcp_param_connectionparam_ps;
1871 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "OS"))
1873 hf_uint = hf_mgcp_param_connectionparam_os;
1875 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PR"))
1877 hf_uint = hf_mgcp_param_connectionparam_pr;
1879 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "OR"))
1881 hf_uint = hf_mgcp_param_connectionparam_or;
1883 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PL"))
1885 hf_uint = hf_mgcp_param_connectionparam_pl;
1887 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "JI"))
1889 hf_uint = hf_mgcp_param_connectionparam_ji;
1891 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "LA"))
1893 hf_uint = hf_mgcp_param_connectionparam_la;
1895 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PC/RPS"))
1897 hf_uint = hf_mgcp_param_connectionparam_pcrps;
1898 } else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PC/ROS"))
1900 hf_uint = hf_mgcp_param_connectionparam_pcros;
1902 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PC/RPL"))
1904 hf_uint = hf_mgcp_param_connectionparam_pcrpl;
1906 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PC/RJI"))
1908 hf_uint = hf_mgcp_param_connectionparam_pcrji;
1910 else if (!g_ascii_strncasecmp(g_strstrip(typval[0]), "X-", 2))
1912 hf_string = hf_mgcp_param_connectionparam_x;
1924 proto_tree_add_uint(tree, hf_uint, tvb, offset, tokenlen, atol(typval[1]));
1926 else if (hf_string != -1)
1928 proto_tree_add_string(tree, hf_string, tvb, offset, tokenlen, g_strstrip(typval[1]));
1932 proto_tree_add_text(tree, tvb, offset, tokenlen, "Unknown parameter: %s", tokens[i]);
1938 proto_tree_add_text(tree, tvb, offset, tokenlen, "Malformed parameter: %s", tokens[i]);
1940 offset += tokenlen + 1; /* 1 extra for the delimiter */
1945 /* Dissect the local connection option */
1947 dissect_mgcp_localconnectionoptions(proto_tree *parent_tree, tvbuff_t *tvb, gint offset, gint param_type_len, gint param_val_len)
1949 proto_tree *tree = parent_tree;
1950 proto_item *item = NULL;
1952 gchar *tokenline = NULL;
1953 gchar **tokens = NULL;
1954 gchar **typval = NULL;
1962 item = proto_tree_add_item(parent_tree, hf_mgcp_param_localconnoptions, tvb, offset, param_type_len+param_val_len, FALSE);
1963 tree = proto_item_add_subtree(item, ett_mgcp_param_localconnectionoptions);
1967 offset += param_type_len; /* skip the L: */
1968 tokenline = tvb_get_ephemeral_string(tvb, offset, param_val_len);
1970 /* Split into type=value pairs separated by comma */
1971 tokens = ep_strsplit(tokenline, ",", -1);
1972 for (i = 0; tokens[i] != NULL; i++)
1977 tokenlen = (int)strlen(tokens[i]);
1978 typval = ep_strsplit(tokens[i], ":", 2);
1979 if ((typval[0] != NULL) && (typval[1] != NULL))
1981 if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "p"))
1983 hf_uint = hf_mgcp_param_localconnoptions_p;
1985 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "a"))
1987 hf_string = hf_mgcp_param_localconnoptions_a;
1989 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "s"))
1991 hf_string = hf_mgcp_param_localconnoptions_s;
1993 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "e"))
1995 hf_string = hf_mgcp_param_localconnoptions_e;
1997 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "sc-rtp"))
1999 hf_string = hf_mgcp_param_localconnoptions_scrtp;
2001 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "sc-rtcp"))
2003 hf_string = hf_mgcp_param_localconnoptions_scrtcp;
2005 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "b"))
2007 hf_string = hf_mgcp_param_localconnoptions_b;
2009 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "es-ccd"))
2011 hf_string = hf_mgcp_param_localconnoptions_esccd;
2013 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "es-cci"))
2015 hf_string = hf_mgcp_param_localconnoptions_escci;
2017 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "dq-gi"))
2019 hf_string = hf_mgcp_param_localconnoptions_dqgi;
2021 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "dq-rd"))
2023 hf_string = hf_mgcp_param_localconnoptions_dqrd;
2025 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "dq-ri"))
2027 hf_string = hf_mgcp_param_localconnoptions_dqri;
2029 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "dq-rr"))
2031 hf_string = hf_mgcp_param_localconnoptions_dqrr;
2033 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "k"))
2035 hf_string = hf_mgcp_param_localconnoptions_k;
2037 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "gc"))
2039 hf_uint = hf_mgcp_param_localconnoptions_gc;
2041 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "fmtp"))
2043 hf_string = hf_mgcp_param_localconnoptions_fmtp;
2045 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "nt"))
2047 hf_string = hf_mgcp_param_localconnoptions_nt;
2049 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "o-fmtp"))
2051 hf_string = hf_mgcp_param_localconnoptions_ofmtp;
2053 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "r"))
2055 hf_string = hf_mgcp_param_localconnoptions_r;
2057 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "t"))
2059 hf_string = hf_mgcp_param_localconnoptions_t;
2061 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "r-cnf"))
2063 hf_string = hf_mgcp_param_localconnoptions_rcnf;
2065 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "r-dir"))
2067 hf_string = hf_mgcp_param_localconnoptions_rdir;
2069 else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "r-sh"))
2071 hf_string = hf_mgcp_param_localconnoptions_rsh;
2084 proto_tree_add_uint(tree, hf_uint, tvb, offset, tokenlen, atol(typval[1]));
2086 else if (hf_string != -1)
2088 proto_tree_add_string(tree, hf_string, tvb, offset, tokenlen, g_strstrip(typval[1]));
2092 proto_tree_add_text(tree, tvb, offset, tokenlen, "Unknown parameter: %s", tokens[i]);
2098 proto_tree_add_text(tree, tvb, offset, tokenlen, "Malformed parameter: %s", tokens[i]);
2100 offset += tokenlen + 1; /* 1 extra for the delimiter */
2107 * tvb_find_null_line - Returns the length from offset to the first null
2108 * line found (a null line is a line that begins
2109 * with a CR or LF. The offset to the first character
2110 * after the null line is written into the gint pointed
2111 * to by next_offset.
2114 * tvb - The tvbuff in which we are looking for a null line.
2115 * offset - The offset in tvb at which we will begin looking for
2117 * len - The maximum distance from offset in tvb that we will look for
2118 * a null line. If it is -1 we will look to the end of the buffer.
2120 * next_offset - The location to write the offset of first character
2121 * FOLLOWING the null line.
2123 * Returns: The length from offset to the first character BEFORE
2126 static gint tvb_find_null_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset)
2128 gint tvb_lineend,tvb_current_len,tvb_linebegin,maxoffset;
2131 tvb_linebegin = offset;
2132 tvb_lineend = tvb_linebegin;
2134 /* Simple setup to allow for the traditional -1 search to the end of the tvbuff */
2137 tvb_current_len = len;
2141 tvb_current_len = tvb_length_remaining(tvb,offset);
2144 maxoffset = (tvb_current_len - 1) + offset;
2146 /* Loop around until we either find a line begining with a carriage return
2147 or newline character or until we hit the end of the tvbuff. */
2150 tvb_linebegin = tvb_lineend;
2151 tvb_current_len = tvb_length_remaining(tvb,tvb_linebegin);
2152 tvb_find_line_end(tvb, tvb_linebegin, tvb_current_len, &tvb_lineend,FALSE);
2153 tempchar = tvb_get_guint8(tvb,tvb_linebegin);
2154 } while (tempchar != '\r' && tempchar != '\n' && tvb_lineend <= maxoffset);
2157 *next_offset = tvb_lineend;
2159 if (tvb_lineend <= maxoffset)
2161 tvb_current_len = tvb_linebegin - offset;
2165 tvb_current_len = tvb_length_remaining(tvb,offset);
2168 return tvb_current_len;
2172 * tvb_find_dot_line - Returns the length from offset to the first line
2173 * containing only a dot (.) character. A line
2174 * containing only a dot is used to indicate a
2175 * separation between multiple MGCP messages
2176 * piggybacked in the same UDP packet.
2179 * tvb - The tvbuff in which we are looking for a dot line.
2180 * offset - The offset in tvb at which we will begin looking for
2182 * len - The maximum distance from offset in tvb that we will look for
2183 * a dot line. If it is -1 we will look to the end of the buffer.
2185 * next_offset - The location to write the offset of first character
2186 * FOLLOWING the dot line.
2188 * Returns: The length from offset to the first character BEFORE
2189 * the dot line or -1 if the character at offset is a .
2190 * followed by a newline or a carriage return.
2192 static gint tvb_find_dot_line(tvbuff_t* tvb, gint offset, gint len, gint* next_offset)
2194 gint tvb_current_offset, tvb_current_len, maxoffset,tvb_len;
2196 tvb_current_offset = offset;
2197 tvb_current_len = len;
2198 tvb_len = tvb_length(tvb);
2202 maxoffset = tvb_len - 1;
2206 maxoffset = (len - 1) + offset;
2208 tvb_current_offset = offset -1;
2212 tvb_current_offset = tvb_find_guint8(tvb, tvb_current_offset+1,
2213 tvb_current_len, '.');
2214 tvb_current_len = maxoffset - tvb_current_offset + 1;
2216 /* If we didn't find a . then break out of the loop */
2217 if (tvb_current_offset == -1)
2222 /* Do we have and characters following the . ? */
2223 if (tvb_current_offset < maxoffset)
2225 tempchar = tvb_get_guint8(tvb,tvb_current_offset+1);
2226 /* Are the characters that follow the dot a newline or carriage return ? */
2227 if (tempchar == '\r' || tempchar == '\n')
2229 /* Do we have any charaters that proceed the . ? */
2230 if (tvb_current_offset == 0)
2236 tempchar = tvb_get_guint8(tvb,tvb_current_offset-1);
2238 /* Are the characters that follow the dot a newline or a
2239 carriage return ? */
2240 if (tempchar == '\r' || tempchar == '\n')
2248 if (tvb_current_offset == maxoffset)
2250 if (tvb_current_offset == 0)
2256 tempchar = tvb_get_guint8(tvb,tvb_current_offset-1);
2257 if (tempchar == '\r' || tempchar == '\n')
2263 } while (tvb_current_offset < maxoffset);
2267 * So now we either have the tvb_current_offset of a . in a dot line
2268 * or a tvb_current_offset of -1
2270 if (tvb_current_offset == -1)
2272 tvb_current_offset = maxoffset +1;
2273 *next_offset = maxoffset + 1;
2277 tvb_find_line_end(tvb,tvb_current_offset,tvb_current_len,next_offset,FALSE);
2280 if (tvb_current_offset == offset)
2282 tvb_current_len = -1;
2286 tvb_current_len = tvb_current_offset - offset;
2289 return tvb_current_len;