2 * RTPproxy command protocol dissector
3 * Copyright 2013, Peter Lemenkov <lemenkov@gmail.com>
5 * This dissector tries to dissect rtpproxy control protocol. Please visit this
6 * link for brief details on the command format:
8 * http://www.rtpproxy.org/wiki/RTPproxy/Protocol
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1999 Gerald Combs
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
35 #include <epan/address.h>
36 #include <epan/packet.h>
37 #include <epan/prefs.h>
38 #include <epan/conversation.h>
39 #include <epan/expert.h>
40 #include <epan/rtp_pt.h>
41 #include <epan/addr_resolv.h>
43 /* For setting up RTP/RTCP dissectors based on the RTPproxy's answers */
44 #include "packet-rtp.h"
45 #include "packet-rtcp.h"
47 void proto_register_rtpproxy(void);
49 static int proto_rtpproxy = -1;
51 static int hf_rtpproxy_cookie = -1;
52 static int hf_rtpproxy_error = -1;
53 static int hf_rtpproxy_status = -1;
54 static int hf_rtpproxy_ok = -1;
55 static int hf_rtpproxy_ipv4 = -1;
56 static int hf_rtpproxy_ipv6 = -1;
57 static int hf_rtpproxy_port = -1;
58 static int hf_rtpproxy_lf = -1;
59 static int hf_rtpproxy_request = -1;
60 static int hf_rtpproxy_command = -1;
61 static int hf_rtpproxy_command_parameters = -1;
62 static int hf_rtpproxy_command_parameter = -1;
63 static int hf_rtpproxy_command_parameter_codec = -1;
64 static int hf_rtpproxy_command_parameter_local_ipv4 = -1;
65 static int hf_rtpproxy_command_parameter_remote_ipv4 = -1;
66 static int hf_rtpproxy_command_parameter_repacketize = -1;
67 static int hf_rtpproxy_command_parameter_dtmf = -1;
68 /* static int hf_rtpproxy_command_parameter_cmap = -1; TODO */
69 static int hf_rtpproxy_command_parameter_proto = -1;
70 static int hf_rtpproxy_command_parameter_transcode = -1;
71 static int hf_rtpproxy_command_parameter_acc = -1;
72 static int hf_rtpproxy_callid = -1;
73 static int hf_rtpproxy_copy_target = -1;
74 static int hf_rtpproxy_playback_filename = -1;
75 static int hf_rtpproxy_playback_codec = -1;
76 static int hf_rtpproxy_notify = -1;
77 static int hf_rtpproxy_notify_ipv4 = -1;
78 static int hf_rtpproxy_notify_ipv6 = -1;
79 static int hf_rtpproxy_notify_port = -1;
80 static int hf_rtpproxy_notify_tag = -1;
81 static int hf_rtpproxy_tag = -1;
82 static int hf_rtpproxy_mediaid = -1;
83 static int hf_rtpproxy_reply = -1;
84 static int hf_rtpproxy_version_request = -1;
85 static int hf_rtpproxy_version_supported = -1;
86 static int hf_rtpproxy_ng_bencode = -1;
89 static expert_field ei_rtpproxy_timeout = EI_INIT;
90 static expert_field ei_rtpproxy_notify_no_ip = EI_INIT;
91 static expert_field ei_rtpproxy_bad_ipv4 = EI_INIT;
92 static expert_field ei_rtpproxy_bad_ipv6 = EI_INIT;
94 /* Request/response tracking */
95 static int hf_rtpproxy_request_in = -1;
96 static int hf_rtpproxy_response_in = -1;
97 static int hf_rtpproxy_response_time = -1;
99 typedef struct _rtpproxy_info {
106 static dissector_handle_t rtcp_handle;
107 static dissector_handle_t rtp_events_handle;
108 static dissector_handle_t rtp_handle;
109 static dissector_handle_t bencode_handle;
111 typedef struct _rtpproxy_conv_info {
113 } rtpproxy_conv_info_t;
116 static const string_string versiontypenames[] = {
117 { "20040107", "Basic RTP proxy functionality" },
118 { "20050322", "Support for multiple RTP streams and MOH" },
119 { "20060704", "Support for extra parameter in the V command" },
120 { "20071116", "Support for RTP re-packetization" },
121 { "20071218", "Support for forking (copying) RTP stream" },
122 { "20080403", "Support for RTP statistics querying" },
123 { "20081102", "Support for setting codecs in the update/lookup command" },
124 { "20081224", "Support for session timeout notifications" },
125 { "20090810", "Support for automatic bridging" },
129 static const value_string commandtypenames[] = {
130 { 'V', "Handshake/Ping" },
131 { 'v', "Handshake/Ping" },
132 { 'U', "Offer/Update" },
133 { 'u', "Offer/Update" },
134 { 'L', "Answer/Lookup" },
135 { 'l', "Answer/Lookup" },
136 { 'I', "Information"},
137 { 'i', "Information"},
138 { 'X', "Close all active sessions"},
139 { 'x', "Close all active sessions"},
140 { 'D', "Delete an active session (Bye/Cancel/Error)"},
141 { 'd', "Delete an active session (Bye/Cancel/Error)"},
142 { 'P', "Start playback (music-on-hold)"},
143 { 'p', "Start playback (music-on-hold)"},
144 { 'S', "Stop playback (music-on-hold)"},
145 { 's', "Stop playback (music-on-hold)"},
146 { 'R', "Start recording"},
147 { 'r', "Start recording"},
148 { 'C', "Copy stream"},
149 { 'c', "Copy stream"},
150 { 'Q', "Query info about a session"},
151 { 'q', "Query info about a session"},
155 static const value_string paramtypenames[] = {
156 /* Official command parameters */
157 {'4', "Remote address is IPv4"},
158 {'6', "Remote address is IPv6"},
159 {'a', "Asymmetric RTP"},
160 {'A', "Asymmetric RTP"},
161 {'b', "Brief stats"},
162 {'B', "Brief stats"},
165 {'e', "External network (non RFC 1918)"},
166 {'E', "External network (non RFC 1918)"},
167 {'i', "Internal network (RFC 1918)"},
168 {'I', "Internal network (RFC 1918)"},
169 {'l', "Local address"},
170 {'L', "Local address"},
171 {'r', "Remote address"},
172 {'R', "Remote address"},
173 {'s', "Symmetric RTP (default)"},
174 {'S', "Symmetric RTP (default)"},
175 {'w', "Weak connection (allows roaming)"},
176 {'W', "Weak connection (allows roaming)"},
177 {'z', "repacketiZe"},
178 {'Z', "repacketiZe"},
179 /* Unofficial command parameters / expensions */
180 {'d', "DTMF payload ID (unofficial extension)"},
181 {'D', "DTMF payload ID (unofficial extension)"},
182 {'m', "codec Mapping (unofficial extension)"},
183 {'M', "codec Mapping (unofficial extension)"},
184 {'p', "Protocol type (unofficial extension)"},
185 {'P', "Protocol type (unofficial extension)"},
186 {'t', "Transcode to (unofficial extension)"},
187 {'T', "Transcode to (unofficial extension)"},
188 {'v', "Accounting (unofficial extension)"},
189 {'V', "Accounting (unofficial extension)"},
193 static const value_string prototypenames[] = {
194 { '0', "UDP (default)"},
199 static const value_string acctypenames[] = {
201 { '1', "Interim update"},
206 static const value_string oktypenames[] = {
208 { '1', "Version Supported"},
212 static const string_string errortypenames[] = {
213 { "E0", "Syntax error" },
214 { "E1", "Syntax error" },
215 { "E2", "Syntax error" },
216 { "E3", "Unknown command" },
217 { "E4", "Syntax error" },
218 { "E5", "Out of memory" },
219 { "E6", "<no description>" },
220 { "E7", "Software error (can't create listener)" },
221 { "E8", "Not Found" },
222 { "E10", "Software error (can't create listener)" },
223 { "E11", "Out of memory" },
224 { "E12", "Out of memory" },
225 { "E13", "Out of memory" },
226 { "E14", "Out of memory" },
230 static gint ett_rtpproxy = -1;
232 static gint ett_rtpproxy_request = -1;
233 static gint ett_rtpproxy_command = -1;
234 static gint ett_rtpproxy_command_parameters = -1;
235 static gint ett_rtpproxy_command_parameters_codecs = -1;
236 static gint ett_rtpproxy_command_parameters_local = -1;
237 static gint ett_rtpproxy_command_parameters_remote = -1;
238 static gint ett_rtpproxy_command_parameters_repacketize = -1;
239 static gint ett_rtpproxy_command_parameters_dtmf = -1;
240 static gint ett_rtpproxy_command_parameters_cmap = -1;
241 static gint ett_rtpproxy_command_parameters_proto = -1;
242 static gint ett_rtpproxy_command_parameters_transcode = -1;
243 static gint ett_rtpproxy_command_parameters_acc = -1;
244 static gint ett_rtpproxy_tag = -1;
245 static gint ett_rtpproxy_notify = -1;
247 static gint ett_rtpproxy_reply = -1;
249 static gint ett_rtpproxy_ng_bencode = -1;
252 static guint rtpproxy_tcp_port = 22222;
253 static guint rtpproxy_udp_port = 22222;
254 static gboolean rtpproxy_establish_conversation = TRUE;
255 /* See - http://www.opensips.org/html/docs/modules/devel/rtpproxy.html#id250016 */
256 /* See - http://www.kamailio.org/docs/modules/devel/modules/rtpproxy.html#idm448 */
257 static guint rtpproxy_timeout = 1000;
258 static nstime_t rtpproxy_timeout_ns = {1, 0};
260 void proto_reg_handoff_rtpproxy(void);
263 rtpproxy_add_tag(proto_tree *rtpproxy_tree, tvbuff_t *tvb, guint begin, guint realsize)
265 proto_item *ti = NULL;
266 proto_tree *another_tree = NULL;
270 new_offset = tvb_find_guint8(tvb, begin, -1, ' ');
272 end = realsize; /* No more parameters */
276 /* SER/OpenSER/OpenSIPS/Kamailio adds Media-ID right after the Tag
277 * separated by a semicolon
279 new_offset = tvb_find_guint8(tvb, begin, end, ';');
280 if(new_offset == -1){
281 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_tag, tvb, begin, end - begin, ENC_ASCII | ENC_NA);
282 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_tag);
283 ti = proto_tree_add_item(another_tree, hf_rtpproxy_mediaid, tvb, new_offset+1, 0, ENC_ASCII | ENC_NA);
284 proto_item_append_text(ti, "<skipped>");
285 PROTO_ITEM_SET_GENERATED(ti);
288 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_tag, tvb, begin, new_offset - begin, ENC_ASCII | ENC_NA);
289 if ((guint)new_offset == begin){
290 proto_item_append_text(ti, "<skipped>"); /* A very first Offer/Update command */
291 PROTO_ITEM_SET_GENERATED(ti);
293 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_tag);
294 proto_tree_add_item(another_tree, hf_rtpproxy_mediaid, tvb, new_offset+1, end - (new_offset+1), ENC_ASCII | ENC_NA);
296 return (end == realsize ? -1 : (gint)end);
300 rtpproxy_add_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *rtpproxy_tree, guint begin, guint realsize)
303 proto_tree *another_tree = NULL;
305 guint new_offset = 0;
308 gchar** codecs = NULL;
310 guint8* rawstr = NULL;
311 guint32 ipaddr[4]; /* Enough room for IPv4 or IPv6 */
313 /* Extract the entire parameters line. */
314 /* Something like "t4p1iic8,0,2,4,18,96,97,98,100,101" */
315 rawstr = tvb_get_string_enc(wmem_packet_scope(), tvb, begin, realsize, ENC_ASCII);
317 while(offset < realsize){
318 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_command_parameter, tvb, begin + offset, 1, ENC_NA);
319 offset++; /* Skip 1-byte parameter's type */
320 switch (g_ascii_tolower(tvb_get_guint8(tvb, begin+offset-1)))
322 /* Official long parameters */
324 new_offset = (gint)strspn(rawstr+offset, "0123456789,");
325 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_codecs);
326 codecs = g_strsplit(tvb_get_string_enc(wmem_packet_scope(), tvb, begin+offset, new_offset, ENC_ASCII), ",", 0);
329 /* We assume strings < 2^32-1 bytes long. :-) */
330 codec_len = (guint)strlen(codecs[i]);
331 ti = proto_tree_add_uint(another_tree, hf_rtpproxy_command_parameter_codec, tvb, begin+offset, codec_len,
332 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin+offset, codec_len, ENC_ASCII), NULL, 10));
333 proto_item_append_text(ti, " (%s)", val_to_str_ext((guint)strtoul(tvb_format_text(tvb,begin+offset,codec_len),NULL,10), &rtp_payload_type_vals_ext, "Unknown"));
336 offset++; /* skip comma */
342 new_offset = (gint)strspn(rawstr+offset, "0123456789.");
343 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_local);
344 if(str_to_ip((char*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin+offset, new_offset, ENC_ASCII), ipaddr))
345 proto_tree_add_ipv4(another_tree, hf_rtpproxy_command_parameter_local_ipv4, tvb, begin+offset, new_offset, ipaddr[0]);
347 proto_tree_add_expert(another_tree, pinfo, &ei_rtpproxy_bad_ipv4, tvb, begin+offset, new_offset);
348 offset += new_offset;
351 new_offset = (gint)strspn(rawstr+offset, "0123456789.");
352 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_remote);
353 if(str_to_ip((char*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin+offset, new_offset, ENC_ASCII), ipaddr))
354 proto_tree_add_ipv4(another_tree, hf_rtpproxy_command_parameter_remote_ipv4, tvb, begin+offset, new_offset, ipaddr[0]);
356 proto_tree_add_expert(another_tree, pinfo, &ei_rtpproxy_bad_ipv4, tvb, begin+offset, new_offset);
357 offset += new_offset;
360 new_offset = (gint)strspn(rawstr+offset, "0123456789");
361 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_repacketize);
362 proto_tree_add_uint(another_tree, hf_rtpproxy_command_parameter_repacketize, tvb, begin+offset, new_offset,
363 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin+offset, new_offset, ENC_ASCII), NULL, 10));
364 offset += new_offset;
366 /* Unofficial long parameters */
368 new_offset = (gint)strspn(rawstr+offset, "0123456789");
369 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_dtmf);
370 proto_tree_add_uint(another_tree, hf_rtpproxy_command_parameter_dtmf, tvb, begin+offset, new_offset,
371 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin+offset, new_offset, ENC_ASCII), NULL, 10));
372 if(rtpproxy_establish_conversation){
373 pt = (guint)strtoul(tvb_format_text(tvb,begin+offset,new_offset),NULL,10);
374 dissector_add_uint("rtp.pt", pt, rtp_events_handle);
376 offset += new_offset;
379 new_offset = (gint)strspn(rawstr+offset, "0123456789=,");
381 offset += new_offset;
384 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_proto);
385 proto_tree_add_item(another_tree, hf_rtpproxy_command_parameter_proto, tvb, begin+offset, 1, ENC_NA);
389 new_offset = (gint)strspn(rawstr+offset, "0123456789");
390 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_transcode);
391 ti = proto_tree_add_uint(another_tree, hf_rtpproxy_command_parameter_transcode, tvb, begin+offset, new_offset,
392 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin+offset, new_offset, ENC_ASCII), NULL, 10));
393 proto_item_append_text(ti, " (%s)", val_to_str_ext((guint)strtoul(tvb_format_text(tvb,begin+offset, new_offset),NULL,10), &rtp_payload_type_vals_ext, "Unknown"));
394 offset += new_offset;
397 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_acc);
398 proto_tree_add_item(another_tree, hf_rtpproxy_command_parameter_acc, tvb, begin+offset, 1, ENC_NA);
407 static rtpproxy_info_t *
408 rtpproxy_add_tid(gboolean is_request, tvbuff_t *tvb, packet_info *pinfo, proto_tree *rtpproxy_tree, rtpproxy_conv_info_t *rtpproxy_conv, gchar* cookie)
410 rtpproxy_info_t *rtpproxy_info;
413 if (!PINFO_FD_VISITED(pinfo)) {
415 rtpproxy_info = wmem_new(wmem_file_scope(), rtpproxy_info_t);
416 rtpproxy_info->req_frame = PINFO_FD_NUM(pinfo);
417 rtpproxy_info->resp_frame = 0;
418 rtpproxy_info->req_time = pinfo->fd->abs_ts;
419 rtpproxy_info->callid = NULL;
420 wmem_tree_insert_string(rtpproxy_conv->trans, cookie, rtpproxy_info, 0);
422 rtpproxy_info = (rtpproxy_info_t *)wmem_tree_lookup_string(rtpproxy_conv->trans, cookie, 0);
424 rtpproxy_info->resp_frame = PINFO_FD_NUM(pinfo);
428 rtpproxy_info = (rtpproxy_info_t *)wmem_tree_lookup_string(rtpproxy_conv->trans, cookie, 0);
429 if (rtpproxy_info && (is_request ? rtpproxy_info->resp_frame : rtpproxy_info->req_frame)) {
432 pi = proto_tree_add_uint(rtpproxy_tree, is_request ? hf_rtpproxy_response_in : hf_rtpproxy_request_in, tvb, 0, 0, is_request ? rtpproxy_info->resp_frame : rtpproxy_info->req_frame);
433 PROTO_ITEM_SET_GENERATED(pi);
435 /* If reply then calculate response time */
437 nstime_delta(&ns, &pinfo->fd->abs_ts, &rtpproxy_info->req_time);
438 pi = proto_tree_add_time(rtpproxy_tree, hf_rtpproxy_response_time, tvb, 0, 0, &ns);
439 PROTO_ITEM_SET_GENERATED(pi);
440 if (nstime_cmp(&rtpproxy_timeout_ns, &ns) < 0)
441 expert_add_info_format(pinfo, rtpproxy_tree, &ei_rtpproxy_timeout, "Response timeout %.3f seconds", nstime_to_sec(&ns));
445 /* Could be NULL so we should check it before dereferencing */
446 return rtpproxy_info;
450 rtpproxy_add_notify_addr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *rtpproxy_tree, guint begin, guint end)
454 gboolean ipv6 = FALSE;
455 guint32 ipaddr[4]; /* Enough room for IPv4 or IPv6 */
458 /* Check for at least one colon */
459 offset = tvb_find_guint8(tvb, begin, end, ':');
461 /* Find if it's the latest colon (not in case of a IPv6) */
462 while((tmp = tvb_find_guint8(tvb, offset+1, end, ':')) != -1){
466 /* We have ip:port */
468 if(str_to_ip6((char*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin, offset - begin, ENC_ASCII), ipaddr))
469 proto_tree_add_ipv6(rtpproxy_tree, hf_rtpproxy_notify_ipv6, tvb, begin, offset - begin, (const guint8 *)ipaddr);
471 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv6, tvb, begin, offset - begin);
474 if(str_to_ip((char*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin, offset - begin, ENC_ASCII), ipaddr))
475 proto_tree_add_ipv4(rtpproxy_tree, hf_rtpproxy_notify_ipv4, tvb, begin, offset - begin, ipaddr[0]);
477 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv4, tvb, begin, offset - begin);
479 proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_notify_port, tvb, offset+1, end - (offset+1),
480 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, offset+1, end - (offset+1), ENC_ASCII), NULL, 10));
483 /* Only port is supplied - take IPv4/IPv6 from ip.src/ipv6.src respectively */
484 expert_add_info(pinfo, rtpproxy_tree, &ei_rtpproxy_notify_no_ip);
485 if (pinfo->src.type == AT_IPv4)
486 ti = proto_tree_add_ipv4(rtpproxy_tree, hf_rtpproxy_notify_ipv4, tvb, begin, 0, ((guint32*)(pinfo->src.data))[0]);
488 ti = proto_tree_add_ipv6(rtpproxy_tree, hf_rtpproxy_notify_ipv6, tvb, begin, 0, (const guint8 *)(pinfo->src.data));
489 PROTO_ITEM_SET_GENERATED(ti);
490 proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_notify_port, tvb, begin, end - begin,
491 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin, end - begin, ENC_ASCII), NULL, 10));
496 dissect_rtpproxy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
498 gboolean has_lf = FALSE;
508 proto_tree *rtpproxy_tree;
509 conversation_t *conversation;
510 rtpproxy_conv_info_t *rtpproxy_conv;
511 gchar* cookie = NULL;
512 /* For RT(C)P setup */
515 guint32 ipaddr[4]; /* Enough room for IPv4 or IPv6 */
516 rtpproxy_info_t *rtpproxy_info = NULL;
519 /* If it does not start with a printable character it's not RTPProxy */
520 if(!isprint(tvb_get_guint8(tvb, 0)))
524 offset = tvb_find_guint8(tvb, offset, -1, ' ');
528 /* Clear out stuff in the info column - we''l set it later */
529 col_clear(pinfo->cinfo, COL_INFO);
531 ti = proto_tree_add_item(tree, proto_rtpproxy, tvb, 0, -1, ENC_NA);
532 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy);
534 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_cookie, tvb, 0, offset, ENC_ASCII | ENC_NA);
535 cookie = tvb_get_string_enc(wmem_packet_scope(), tvb, 0, offset, ENC_ASCII);
537 /* Skip whitespace */
538 offset = tvb_skip_wsp(tvb, offset+1, -1);
540 /* Calculate size to prevent recalculation in the future */
541 realsize = tvb_reported_length(tvb);
544 /* Check for LF (required for TCP connection, optional for UDP) */
545 if (tvb_get_guint8(tvb, realsize - 1) == '\n'){
546 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTPproxy");
547 /* Don't count trailing LF */
552 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTPproxy (no LF)"); /* FIXME replace with expert info field */
555 /* Try to create conversation */
556 conversation = find_or_create_conversation(pinfo);
557 rtpproxy_conv = (rtpproxy_conv_info_t *)conversation_get_proto_data(conversation, proto_rtpproxy);
558 if (!rtpproxy_conv) {
559 rtpproxy_conv = wmem_new(wmem_file_scope(), rtpproxy_conv_info_t);
560 rtpproxy_conv->trans = wmem_tree_new(wmem_file_scope());
561 conversation_add_proto_data(conversation, proto_rtpproxy, rtpproxy_conv);
564 /* Get payload string */
565 rawstr = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, realsize - offset, ENC_ASCII);
567 /* Extract command */
568 tmp = g_ascii_tolower(tvb_get_guint8(tvb, offset));
572 /* A specific case - long statistics answer */
573 /* %COOKIE% sessions created %NUM0% active sessions: %NUM1% */
574 rtpproxy_add_tid(FALSE, tvb, pinfo, rtpproxy_tree, rtpproxy_conv, cookie);
575 if ('e' == tvb_get_guint8(tvb, offset+1)){
576 col_add_fstr(pinfo->cinfo, COL_INFO, "Reply: %s", rawstr);
577 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_reply, tvb, offset, -1, ENC_NA);
579 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_reply);
580 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_status, tvb, offset, realsize - offset, ENC_ASCII | ENC_NA);
588 tmp2 = tvb_get_guint8(tvb, offset+1);
589 if(('1' <= tmp2) && (tmp2 <= '9') && (tvb_get_guint8(tvb, offset+2) == ':')){
590 col_add_fstr(pinfo->cinfo, COL_INFO, "RTPproxy-ng: %s", rawstr);
591 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_ng_bencode, tvb, offset, -1, ENC_ASCII | ENC_NA);
592 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_ng_bencode);
593 subtvb = tvb_new_subset_remaining(tvb, offset);
594 call_dissector(bencode_handle, subtvb, pinfo, rtpproxy_tree);
602 rtpproxy_info = rtpproxy_add_tid(TRUE, tvb, pinfo, rtpproxy_tree, rtpproxy_conv, cookie);
603 col_add_fstr(pinfo->cinfo, COL_INFO, "Request: %s", rawstr);
604 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_request, tvb, offset, -1, ENC_NA);
605 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_request);
607 /* A specific case - version request */
608 if ((tmp == 'v') && (offset + (gint)strlen("VF YYYMMDD") + 1 == realsize)){
609 /* Skip whitespace */
610 new_offset = tvb_skip_wsp(tvb, offset + ((guint)strlen("VF") + 1), -1);
611 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_version_request, tvb, new_offset, (gint)strlen("YYYYMMDD"), ENC_ASCII | ENC_NA);
612 tmpstr = tvb_get_string_enc(wmem_packet_scope(), tvb, new_offset, (gint)strlen("YYYYMMDD"), ENC_ASCII);
613 proto_item_append_text(ti, " (%s)", str_to_str(tmpstr, versiontypenames, "Unknown"));
617 /* All other commands */
618 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_command, tvb, offset, 1, ENC_NA);
620 /* A specific case - handshake/ping */
622 break; /* No more parameters */
624 /* A specific case - close all calls */
626 break; /* No more parameters */
628 /* Extract parameters */
629 /* Parameters should be right after the command and before EOL (in case of Info command) or before whitespace */
630 new_offset = (tmp == 'i' ? (realsize - 1 > offset ? offset + (gint)strlen("Ib") : offset + (gint)strlen("I")) : tvb_find_guint8(tvb, offset, -1, ' '));
632 if (new_offset != offset + 1){
633 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_command);
634 ti2 = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_command_parameters, tvb, offset+1, new_offset - (offset+1), ENC_ASCII | ENC_NA);
635 rtpproxy_add_parameter(tvb, pinfo, proto_item_add_subtree(ti2, ett_rtpproxy_command_parameters), offset+1, new_offset - (offset+1));
636 rtpproxy_tree = proto_item_get_parent(ti);
639 /* A specific case - query information */
641 break; /* No more parameters */
643 /* Skip whitespace */
644 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
646 /* Extract Call-ID */
647 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
648 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_callid, tvb, offset, new_offset - offset, ENC_ASCII | ENC_NA);
649 if(rtpproxy_info && !rtpproxy_info->callid)
650 rtpproxy_info->callid = tvb_get_string_enc(wmem_file_scope(), tvb, offset, new_offset - offset, ENC_ASCII);
651 /* Skip whitespace */
652 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
654 /* Extract IP and Port in case of Offer/Answer */
655 if ((tmp == 'u') || (tmp == 'l')){
657 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
658 if (tvb_find_guint8(tvb, offset, new_offset - offset, ':') == -1){
659 if(str_to_ip((char*)tvb_get_string_enc(wmem_packet_scope(), tvb, offset, new_offset - offset, ENC_ASCII), ipaddr))
660 proto_tree_add_ipv4(rtpproxy_tree, hf_rtpproxy_ipv4, tvb, offset, new_offset - offset, ipaddr[0]);
662 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv4, tvb, offset, new_offset - offset);
665 if(str_to_ip6((char*)tvb_get_string_enc(wmem_packet_scope(), tvb, offset, new_offset - offset, ENC_ASCII), ipaddr))
666 proto_tree_add_ipv6(rtpproxy_tree, hf_rtpproxy_ipv6, tvb, offset, new_offset - offset, (const guint8 *)ipaddr);
668 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv6, tvb, offset, new_offset - offset);
670 /* Skip whitespace */
671 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
674 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
675 proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_port, tvb, offset, new_offset - offset,
676 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, offset, new_offset - offset, ENC_ASCII), NULL, 10));
677 /* Skip whitespace */
678 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
681 /* Extract Copy target */
683 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
684 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_copy_target, tvb, offset, new_offset - offset, ENC_ASCII | ENC_NA);
685 /* Skip whitespace */
686 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
689 /* Extract Playback file and codecs */
691 /* Extract filename */
692 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
693 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_playback_filename, tvb, offset, new_offset - offset, ENC_ASCII | ENC_NA);
694 /* Skip whitespace */
695 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
698 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
699 proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_playback_codec, tvb, offset, new_offset - offset,
700 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, offset, new_offset - offset, ENC_ASCII), NULL, 10));
701 /* Skip whitespace */
702 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
705 /* Extract first tag */
706 new_offset = rtpproxy_add_tag(rtpproxy_tree, tvb, offset, realsize);
708 break; /* No more parameters */
709 /* Skip whitespace */
710 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
712 /* Extract second tag */
713 new_offset = rtpproxy_add_tag(rtpproxy_tree, tvb, offset, realsize);
715 break; /* No more parameters */
716 /* Skip whitespace */
717 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
719 /* Extract Notification address */
721 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_notify, tvb, offset, realsize - offset, ENC_ASCII | ENC_NA);
722 proto_item_set_text(ti, "Notify");
723 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_notify);
725 /* Check for NotifyTag parameter (separated by space) */
726 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
727 if(new_offset == -1){
728 /* NotifyTag wasn't found (we should re-use Call-ID instead) */
729 rtpproxy_add_notify_addr(tvb, pinfo, rtpproxy_tree, offset, realsize);
730 break; /* No more parameters */
733 /* NotifyTag was found */
734 rtpproxy_add_notify_addr(tvb, pinfo, rtpproxy_tree, offset, new_offset);
735 /* Skip whitespace */
736 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
738 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_notify_tag, tvb, offset, realsize - offset, ENC_ASCII | ENC_NA);
753 rtpproxy_info = rtpproxy_add_tid(FALSE, tvb, pinfo, rtpproxy_tree, rtpproxy_conv, cookie);
755 col_add_fstr(pinfo->cinfo, COL_INFO, "Error reply: %s", rawstr);
757 col_add_fstr(pinfo->cinfo, COL_INFO, "Reply: %s", rawstr);
759 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_reply, tvb, offset, -1, ENC_NA);
760 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_reply);
762 if(rtpproxy_info && rtpproxy_info->callid){
763 ti = proto_tree_add_string(rtpproxy_tree, hf_rtpproxy_callid, tvb, offset, 0, rtpproxy_info->callid);
764 PROTO_ITEM_SET_GENERATED(ti);
768 tmp = tvb_find_line_end(tvb, offset, -1, &new_offset, FALSE);
769 tmpstr = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, tmp, ENC_ASCII);
770 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_error, tvb, offset, (gint)strlen(tmpstr), ENC_ASCII | ENC_NA);
771 proto_item_append_text(ti, " (%s)", str_to_str(tmpstr, errortypenames, "Unknown"));
776 /* A specific case - short statistics answer */
777 /* %COOKIE% active sessions: %NUM1% */
778 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_status, tvb, offset, realsize - offset, ENC_ASCII | ENC_NA);
781 if ((tmp == '0')&& ((tvb_reported_length(tvb) == (guint)(offset+1))||(tvb_reported_length(tvb) == (guint)(offset+2)))){
782 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_ok, tvb, offset, 1, ENC_ASCII | ENC_NA);
785 if ((tmp == '1') && ((tvb_reported_length(tvb) == (guint)(offset+1))||(tvb_reported_length(tvb) == (guint)(offset+2)))){
786 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_ok, tvb, offset, 1, ENC_ASCII | ENC_NA);
789 if (tvb_reported_length(tvb) == (guint)(offset+9)){
790 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_version_supported, tvb, offset, 8, ENC_ASCII | ENC_NA);
795 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
796 /* Convert port to unsigned 16-bit number */
797 port = (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, offset, new_offset - offset, ENC_ASCII), NULL, 10);
798 proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_port, tvb, offset, new_offset - offset, port);
799 /* Skip whitespace */
800 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
803 memset(&addr, 0, sizeof(address));
805 /* Try rtpengine bogus extension first. It appends 4 or
806 * 6 depending on type of the IP. See
807 * https://github.com/sipwise/rtpengine/blob/master/daemon/call_interfaces.c#L66
808 * for further details */
809 tmp = tvb_find_guint8(tvb, offset, -1, ' ');
810 if(tmp == (guint)(-1)){
811 /* No extension - operate normally */
812 tmp = tvb_find_line_end(tvb, offset, -1, &new_offset, FALSE);
818 if (tvb_find_guint8(tvb, offset, -1, ':') == -1){
819 if (str_to_ip((char*)tvb_get_string_enc(wmem_packet_scope(), tvb, offset, tmp, ENC_ASCII), ipaddr)){
822 addr.data = wmem_memdup(wmem_packet_scope(), ipaddr, 4);
823 proto_tree_add_ipv4(rtpproxy_tree, hf_rtpproxy_ipv4, tvb, offset, tmp, ipaddr[0]);
826 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv4, tvb, offset, tmp);
829 if (str_to_ip6((char*)tvb_get_string_enc(wmem_packet_scope(), tvb, offset, tmp, ENC_ASCII), ipaddr)){
832 addr.data = wmem_memdup(wmem_packet_scope(), ipaddr, 16);
833 proto_tree_add_ipv6(rtpproxy_tree, hf_rtpproxy_ipv6, tvb, offset, tmp, (const guint8 *)ipaddr);
836 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv6, tvb, offset, tmp);
839 if(rtpproxy_establish_conversation){
841 /* FIXME tell if isn't a video stream, and setup codec mapping */
843 rtp_add_address(pinfo, &addr, port, 0, "RTPproxy", pinfo->fd->num, 0, NULL);
847 rtcp_add_address(pinfo, &addr, port+1, 0, "RTPproxy", pinfo->fd->num);
855 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_lf, tvb, realsize, 1, ENC_NA);
857 return tvb_length(tvb);
861 proto_register_rtpproxy(void)
863 module_t *rtpproxy_module;
864 expert_module_t* expert_rtpproxy_module;
866 static hf_register_info hf[] = {
881 &hf_rtpproxy_version_request,
894 &hf_rtpproxy_version_supported,
897 "rtpproxy.version_supported",
976 FT_UINT16, /* 0 - 65535 */
985 &hf_rtpproxy_request,
998 &hf_rtpproxy_command,
1004 VALS(commandtypenames),
1011 &hf_rtpproxy_command_parameters,
1013 "Command parameters",
1014 "rtpproxy.command_parameters",
1024 &hf_rtpproxy_command_parameter,
1027 "rtpproxy.command_parameter",
1030 VALS(paramtypenames),
1037 &hf_rtpproxy_command_parameter_codec,
1040 "rtpproxy.command_parameter_codec",
1041 FT_UINT8, /* 0 - 127 */
1050 &hf_rtpproxy_command_parameter_local_ipv4,
1052 "Local IPv4 address",
1053 "rtpproxy.command_parameter_local_ipv4",
1054 FT_IPv4, /* FIXME - is it ever possible to see IPv6 here? */
1063 &hf_rtpproxy_command_parameter_remote_ipv4,
1065 "Remote IPv4 address",
1066 "rtpproxy.command_parameter_remote_ipv4",
1067 FT_IPv4, /* FIXME - is it ever possible to see IPv6 here? */
1076 &hf_rtpproxy_command_parameter_repacketize,
1079 "rtpproxy.command_parameter_repacketize",
1080 FT_UINT16, /* 0 - 1000 milliseconds */
1089 &hf_rtpproxy_command_parameter_dtmf,
1092 "rtpproxy.command_parameter_dtmf",
1093 FT_UINT8, /* 0 - 127 */
1102 &hf_rtpproxy_command_parameter_proto,
1104 "RTP tramsission protocol",
1105 "rtpproxy.command_parameter_proto",
1108 VALS(prototypenames),
1115 &hf_rtpproxy_command_parameter_transcode,
1118 "rtpproxy.command_parameter_transcode",
1119 FT_UINT8, /* 0 - 127 */
1128 &hf_rtpproxy_command_parameter_acc,
1131 "rtpproxy.command_parameter_acc",
1141 &hf_rtpproxy_copy_target,
1144 "rtpproxy.copy_target",
1145 FT_STRING, /* Filename or UDP address, e.g. /var/tmp/fileXXXX.yyy or IP:Port */
1154 &hf_rtpproxy_playback_filename,
1156 "Playback filename",
1157 "rtpproxy.playback_filename",
1167 &hf_rtpproxy_playback_codec,
1170 "rtpproxy.playback_codec",
1171 FT_UINT8, /* 0 - 127 */
1180 &hf_rtpproxy_callid,
1193 &hf_rtpproxy_notify,
1219 &hf_rtpproxy_mediaid,
1232 &hf_rtpproxy_notify_ipv4,
1234 "Notification IPv4",
1235 "rtpproxy.notify_ipv4",
1245 &hf_rtpproxy_notify_ipv6,
1247 "Notification IPv6",
1248 "rtpproxy.notify_ipv6",
1258 &hf_rtpproxy_notify_port,
1260 "Notification Port",
1261 "rtpproxy.notify_port",
1271 &hf_rtpproxy_notify_tag,
1274 "rtpproxy.notify_tag",
1310 &hf_rtpproxy_request_in,
1313 "rtpproxy.request_in",
1324 &hf_rtpproxy_response_in,
1327 "rtpproxy.response_in",
1337 &hf_rtpproxy_response_time,
1340 "rtpproxy.response_time",
1345 "The time between the Request and the Reply",
1350 &hf_rtpproxy_ng_bencode,
1352 "RTPproxy-ng bencode packet",
1353 "rtpproxy.ng.bencode",
1358 "Serialized structure of integers, dictionaries, strings and lists.",
1364 static ei_register_info ei[] = {
1365 { &ei_rtpproxy_timeout, { "rtpproxy.response_timeout", PI_RESPONSE_CODE, PI_WARN, "TIMEOUT", EXPFILL }},
1366 { &ei_rtpproxy_notify_no_ip, { "rtpproxy.notify_no_ip", PI_RESPONSE_CODE, PI_COMMENT, "No notification IP address provided. Using ip.src or ipv6.src as a value.", EXPFILL }},
1367 { &ei_rtpproxy_bad_ipv4, { "rtpproxy.bad_ipv4", PI_MALFORMED, PI_ERROR, "Bad IPv4", EXPFILL }},
1368 { &ei_rtpproxy_bad_ipv6, { "rtpproxy.bad_ipv6", PI_MALFORMED, PI_ERROR, "Bad IPv6", EXPFILL }},
1371 /* Setup protocol subtree array */
1372 static gint *ett[] = {
1374 &ett_rtpproxy_request,
1375 &ett_rtpproxy_command,
1376 &ett_rtpproxy_command_parameters,
1377 &ett_rtpproxy_command_parameters_codecs,
1378 &ett_rtpproxy_command_parameters_local,
1379 &ett_rtpproxy_command_parameters_remote,
1380 &ett_rtpproxy_command_parameters_repacketize,
1381 &ett_rtpproxy_command_parameters_dtmf,
1382 &ett_rtpproxy_command_parameters_cmap,
1383 &ett_rtpproxy_command_parameters_proto,
1384 &ett_rtpproxy_command_parameters_transcode,
1385 &ett_rtpproxy_command_parameters_acc,
1387 &ett_rtpproxy_notify,
1388 &ett_rtpproxy_reply,
1389 &ett_rtpproxy_ng_bencode
1392 proto_rtpproxy = proto_register_protocol (
1393 "Sippy RTPproxy Protocol", /* name */
1394 "RTPproxy", /* short name */
1395 "rtpproxy" /* abbrev */
1398 proto_register_field_array(proto_rtpproxy, hf, array_length(hf));
1399 proto_register_subtree_array(ett, array_length(ett));
1401 expert_rtpproxy_module = expert_register_protocol(proto_rtpproxy);
1402 expert_register_field_array(expert_rtpproxy_module, ei, array_length(ei));
1404 rtpproxy_module = prefs_register_protocol(proto_rtpproxy, proto_reg_handoff_rtpproxy);
1406 prefs_register_uint_preference(rtpproxy_module, "tcp.port",
1407 "RTPproxy TCP Port", /* Title */
1408 "RTPproxy TCP Port", /* Descr */
1410 &rtpproxy_tcp_port);
1412 prefs_register_uint_preference(rtpproxy_module, "udp.port",
1413 "RTPproxy UDP Port", /* Title */
1414 "RTPproxy UDP Port", /* Descr */
1416 &rtpproxy_udp_port);
1418 prefs_register_bool_preference(rtpproxy_module, "establish_conversation",
1419 "Establish Media Conversation",
1420 "Specifies that RTP/RTCP/T.38/MSRP/etc streams are decoded based "
1421 "upon port numbers found in RTPproxy answers",
1422 &rtpproxy_establish_conversation);
1424 prefs_register_uint_preference(rtpproxy_module, "reply.timeout",
1425 "RTPproxy reply timeout", /* Title */
1426 "Maximum timeout value in waiting for reply from RTPProxy (in milliseconds).", /* Descr */
1432 proto_reg_handoff_rtpproxy(void)
1434 static guint old_rtpproxy_tcp_port = 0;
1435 static guint old_rtpproxy_udp_port = 0;
1437 static gboolean rtpproxy_initialized = FALSE;
1439 static dissector_handle_t rtpproxy_tcp_handle, rtpproxy_udp_handle;
1441 if(!rtpproxy_initialized){
1442 rtpproxy_tcp_handle = new_create_dissector_handle(dissect_rtpproxy, proto_rtpproxy);
1443 rtpproxy_udp_handle = new_create_dissector_handle(dissect_rtpproxy, proto_rtpproxy);
1444 rtpproxy_initialized = TRUE;
1447 /* Register TCP port for dissection */
1448 if(old_rtpproxy_tcp_port != 0 && old_rtpproxy_tcp_port != rtpproxy_tcp_port)
1449 dissector_delete_uint("tcp.port", old_rtpproxy_tcp_port, rtpproxy_tcp_handle);
1450 if(rtpproxy_tcp_port != 0 && old_rtpproxy_tcp_port != rtpproxy_tcp_port)
1451 dissector_add_uint("tcp.port", rtpproxy_tcp_port, rtpproxy_tcp_handle);
1452 old_rtpproxy_tcp_port = rtpproxy_tcp_port;
1454 /* Register UDP port for dissection */
1455 if(old_rtpproxy_udp_port != 0 && old_rtpproxy_udp_port != rtpproxy_udp_port)
1456 dissector_delete_uint("udp.port", old_rtpproxy_udp_port, rtpproxy_udp_handle);
1457 if(rtpproxy_udp_port != 0 && old_rtpproxy_udp_port != rtpproxy_udp_port)
1458 dissector_add_uint("udp.port", rtpproxy_udp_port, rtpproxy_udp_handle);
1459 old_rtpproxy_udp_port = rtpproxy_udp_port;
1461 rtcp_handle = find_dissector("rtcp");
1462 rtp_events_handle = find_dissector("rtpevent");
1463 rtp_handle = find_dissector("rtp");
1464 bencode_handle = find_dissector("bencode");
1466 /* Calculate nstime_t struct for the timeout from the rtpproxy_timeout value in milliseconds */
1467 rtpproxy_timeout_ns.secs = (rtpproxy_timeout - rtpproxy_timeout % 1000) / 1000;
1468 rtpproxy_timeout_ns.nsecs = (rtpproxy_timeout % 1000) * 1000;
1472 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1477 * indent-tabs-mode: t
1480 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1481 * :indentSize=8:tabSize=8:noTabs=false: