summaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-rtp.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
commite4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch)
tree68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/dissectors/packet-rtp.c
parentInitial commit. (diff)
downloadwireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz
wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/dissectors/packet-rtp.c')
-rw-r--r--epan/dissectors/packet-rtp.c3696
1 files changed, 3696 insertions, 0 deletions
diff --git a/epan/dissectors/packet-rtp.c b/epan/dissectors/packet-rtp.c
new file mode 100644
index 00000000..9f7ecea1
--- /dev/null
+++ b/epan/dissectors/packet-rtp.c
@@ -0,0 +1,3696 @@
+/* packet-rtp.c
+ *
+ * Routines for RTP dissection
+ * RTP = Real time Transport Protocol
+ *
+ * Copyright 2000, Philips Electronics N.V.
+ * Written by Andreas Sikkema <h323@ramdyne.nl>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+/*
+ * This dissector tries to dissect the RTP protocol according to Annex A
+ * of ITU-T Recommendation H.225.0 (02/98) or RFC 3550 (obsoleting 1889).
+ *
+ * RTP traffic is traditionally handled by an even UDP portnumber. This can
+ * be any port number, but there is a registered port available, port 5004
+ * See Annex B of ITU-T Recommendation H.225.0, section B.7
+ *
+ * Note that nowadays RTP and RTCP are often multiplexed onto a single port,
+ * per RFC 5671.
+ *
+ * This doesn't dissect older versions of RTP, such as:
+ *
+ * the vat protocol ("version 0") - see
+ *
+ * ftp://ftp.ee.lbl.gov/conferencing/vat/alpha-test/vatsrc-4.0b2.tar.gz
+ *
+ * and look in "session-vat.cc" if you want to write a dissector
+ * (have fun - there aren't any nice header files showing the packet
+ * format);
+ *
+ * version 1, as documented in
+ *
+ * ftp://gaia.cs.umass.edu/pub/hgschulz/rtp/draft-ietf-avt-rtp-04.txt
+ *
+ * It also dissects PacketCable CCC-encapsulated RTP data, as described in
+ * chapter 5 of the PacketCable Electronic Surveillance Specification:
+ *
+ * http://www.packetcable.com/downloads/specs/PKT-SP-ESP1.5-I01-050128.pdf
+ */
+
+
+#include "config.h"
+
+#include <epan/packet.h>
+#include <epan/exceptions.h>
+#include <epan/show_exception.h>
+#include <epan/expert.h>
+#include <epan/proto_data.h>
+#include <epan/decode_as.h>
+
+#include "packet-rtp.h"
+#include "packet-rtcp.h"
+#include "packet-tcp.h"
+
+#include <epan/rtp_pt.h>
+#include <epan/tap.h>
+#include <epan/prefs.h>
+
+/* un-comment the following as well as this line in conversation.c, to enable debug printing */
+/* #define DEBUG_CONVERSATION */
+#include "conversation_debug.h"
+
+/* uncomment this to enable debugging of fragment reassembly */
+/* #define DEBUG 1 */
+/* #define DEBUG_FRAGMENTS 1 */
+
+typedef struct _rfc2198_hdr {
+ unsigned int pt;
+ int offset;
+ int len;
+ const char* payload_type_str;
+ int payload_rate;
+ unsigned payload_channels;
+ wmem_map_t *payload_fmtp_map;
+ struct _rfc2198_hdr *next;
+} rfc2198_hdr;
+
+/* we have one of these for each pdu which spans more than one segment
+ */
+typedef struct _rtp_multisegment_pdu {
+ /* the seqno of the segment where the pdu starts */
+ guint32 startseq;
+
+ /* the seqno of the segment where the pdu ends */
+ guint32 endseq;
+} rtp_multisegment_pdu;
+
+typedef struct _rtp_private_conv_info {
+ /* This tree is indexed by sequence number and keeps track of all
+ * all pdus spanning multiple segments for this flow.
+ */
+ wmem_tree_t *multisegment_pdus;
+} rtp_private_conv_info;
+
+typedef struct _rtp_number_space {
+
+ uint32_t extended_seqno;
+ uint64_t extended_timestamp;
+} rtp_number_space;
+
+/** Info to save in RTP conversation */
+struct _rtp_conversation_info
+{
+ gchar method[MAX_RTP_SETUP_METHOD_SIZE + 1];
+ guint32 frame_number; /**> the frame where this conversation is started */
+ guint32 media_types;
+ rtp_dyn_payload_t* rtp_dyn_payload; /**> the dynamic RTP payload info - see comments above */
+
+ wmem_map_t* ssrc_number_space; /**> maps the SSRCs to the last seen seqno and timestamp
+ * for that SSRC in the conversation */
+ struct _rtp_private_conv_info* rtp_conv_info; /**> conversation info private
+ * to the rtp dissector
+ */
+ struct srtp_info* srtp_info; /* SRTP context */
+ bta2dp_codec_info_t* bta2dp_info;
+ btvdp_codec_info_t* btvdp_info;
+ wmem_array_t* rtp_sdp_setup_info_list; /**> List with data from all SDP occurencies for this steram holding a call ID)*/
+};
+
+typedef struct {
+ char *encoding_name;
+ int sample_rate;
+ unsigned channels;
+ wmem_map_t *fmtp_map;
+} encoding_name_and_rate_t;
+
+struct _rtp_dyn_payload_t
+{
+ GHashTable *table;
+ size_t ref_count;
+};
+
+static reassembly_table rtp_reassembly_table;
+
+static int hf_rtp_fragments = -1;
+static int hf_rtp_fragment = -1;
+static int hf_rtp_fragment_overlap = -1;
+static int hf_rtp_fragment_overlap_conflict = -1;
+static int hf_rtp_fragment_multiple_tails = -1;
+static int hf_rtp_fragment_too_long_fragment = -1;
+static int hf_rtp_fragment_error = -1;
+static int hf_rtp_fragment_count = -1;
+static int hf_rtp_reassembled_in = -1;
+static int hf_rtp_reassembled_length = -1;
+
+static gint ett_rtp_fragment = -1;
+static gint ett_rtp_fragments = -1;
+
+static const fragment_items rtp_fragment_items = {
+ &ett_rtp_fragment,
+ &ett_rtp_fragments,
+ &hf_rtp_fragments,
+ &hf_rtp_fragment,
+ &hf_rtp_fragment_overlap,
+ &hf_rtp_fragment_overlap_conflict,
+ &hf_rtp_fragment_multiple_tails,
+ &hf_rtp_fragment_too_long_fragment,
+ &hf_rtp_fragment_error,
+ &hf_rtp_fragment_count,
+ &hf_rtp_reassembled_in,
+ &hf_rtp_reassembled_length,
+ /* Reassembled data field */
+ NULL,
+ "RTP fragments"
+};
+
+static dissector_handle_t rtp_handle;
+static dissector_handle_t rtp_rfc4571_handle;
+static dissector_handle_t rtcp_handle;
+static dissector_handle_t classicstun_handle;
+static dissector_handle_t stun_handle;
+static dissector_handle_t classicstun_heur_handle;
+static dissector_handle_t stun_heur_handle;
+static dissector_handle_t t38_handle;
+static dissector_handle_t zrtp_handle;
+static dissector_handle_t dtls_handle;
+static dissector_handle_t rtp_rfc2198_handle;
+
+static dissector_handle_t sprt_handle;
+static dissector_handle_t v150fw_handle;
+
+static dissector_handle_t bta2dp_content_protection_header_scms_t;
+static dissector_handle_t btvdp_content_protection_header_scms_t;
+static dissector_handle_t bta2dp_handle;
+static dissector_handle_t btvdp_handle;
+static dissector_handle_t sbc_handle;
+
+static int rtp_tap = -1;
+
+static dissector_table_t rtp_pt_dissector_table;
+static dissector_table_t rtp_dyn_pt_dissector_table;
+
+static dissector_table_t rtp_hdr_ext_dissector_table;
+static dissector_table_t rtp_hdr_ext_rfc5285_dissector_table;
+
+/* Used for storing data to be retreived by the SDP dissector*/
+static int proto_sdp = -1;
+
+/* RTP header fields */
+static int proto_rtp = -1;
+static int proto_rtp_rfc2198 = -1;
+static int hf_rtp_version = -1;
+static int hf_rtp_padding = -1;
+static int hf_rtp_extension = -1;
+static int hf_rtp_csrc_count = -1;
+static int hf_rtp_marker = -1;
+static int hf_rtp_payload_type = -1;
+static int hf_rtp_seq_nr = -1;
+static int hf_rtp_ext_seq_nr = -1;
+static int hf_rtp_timestamp = -1;
+static int hf_rtp_ssrc = -1;
+static int hf_rtp_csrc_items = -1;
+static int hf_rtp_csrc_item = -1;
+static int hf_rtp_data = -1;
+static int hf_rtp_padding_data = -1;
+static int hf_rtp_padding_count= -1;
+static int hf_rtp_rfc2198_follow= -1;
+static int hf_rtp_rfc2198_tm_off= -1;
+static int hf_rtp_rfc2198_bl_len= -1;
+
+/* RTP header extension fields */
+static int hf_rtp_prof_define = -1;
+static int hf_rtp_length = -1;
+static int hf_rtp_hdr_exts = -1;
+static int hf_rtp_hdr_ext = -1;
+
+/* RTP setup fields */
+static int hf_rtp_setup = -1;
+static int hf_rtp_setup_frame = -1;
+static int hf_rtp_setup_method = -1;
+
+/* RTP fields defining a sub tree */
+static gint ett_rtp = -1;
+static gint ett_csrc_list = -1;
+static gint ett_hdr_ext = -1;
+static gint ett_hdr_ext_rfc5285 = -1;
+static gint ett_rtp_setup = -1;
+static gint ett_rtp_rfc2198 = -1;
+static gint ett_rtp_rfc2198_hdr = -1;
+
+/* SRTP fields */
+static int hf_srtp_encrypted_payload = -1;
+/* static int hf_srtp_null_encrypted_payload = -1; */
+static int hf_srtp_mki = -1;
+static int hf_srtp_auth_tag = -1;
+
+/* PacketCable CCC header fields */
+static int proto_pkt_ccc = -1;
+static int hf_pkt_ccc_id = -1;
+static int hf_pkt_ccc_ts = -1;
+
+/* PacketCable CCC field defining a sub tree */
+static gint ett_pkt_ccc = -1;
+
+static expert_field ei_rtp_fragment_unfinished = EI_INIT;
+static expert_field ei_rtp_padding_missing = EI_INIT;
+
+/* RFC 5285 Header extensions */
+static int hf_rtp_ext_rfc5285_id = -1;
+static int hf_rtp_ext_rfc5285_length = -1;
+static int hf_rtp_ext_rfc5285_appbits = -1;
+static int hf_rtp_ext_rfc5285_data = -1;
+
+/* RFC 4571 Header extension */
+static int hf_rfc4571_header_len = -1;
+
+#define RTP0_INVALID 0
+#define RTP0_STUN 1
+#define RTP0_CLASSICSTUN 2
+#define RTP0_T38 3
+#define RTP0_SPRT 4
+#define RTP0_RFC7983 5
+
+static const enum_val_t rtp_version0_types[] = {
+ { "invalid", "Invalid or ZRTP packets", RTP0_INVALID },
+ { "stun", "STUN packets", RTP0_STUN },
+ { "classicstun", "CLASSIC-STUN packets", RTP0_CLASSICSTUN },
+ { "t38", "T.38 packets", RTP0_T38 },
+ { "sprt", "SPRT packets", RTP0_SPRT },
+ { "rfc7983", "Multiplexed as in RFC 7983", RTP0_RFC7983 },
+ { NULL, NULL, 0 }
+};
+static gint global_rtp_version0_type = 5;
+
+/* Forward declaration we need below */
+void proto_register_rtp(void);
+void proto_reg_handoff_rtp(void);
+void proto_register_pkt_ccc(void);
+void proto_reg_handoff_pkt_ccc(void);
+
+static gint dissect_rtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
+static void show_setup_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
+static struct _rtp_packet_info *get_rtp_packet_info(packet_info *pinfo, struct _rtp_info *rtp_info);
+
+/* Preferences bool to control whether or not setup info should be shown */
+static gboolean global_rtp_show_setup_info = TRUE;
+
+/* desegment RTP streams */
+static gboolean desegment_rtp = TRUE;
+
+/* RFC2198 Redundant Audio Data */
+#define RFC2198_DEFAULT_PT_RANGE "99"
+
+static gboolean rfc2198_deencapsulate = TRUE;
+
+
+
+/*
+ * Fields in the first octet of the RTP header.
+ */
+
+/* Version is the first 2 bits of the first octet*/
+#define RTP_VERSION(octet) ((octet) >> 6)
+
+/* Padding is the third bit; No need to shift, because true is any value
+ other than 0! */
+#define RTP_PADDING(octet) ((octet) & 0x20)
+
+/* Extension bit is the fourth bit */
+#define RTP_EXTENSION(octet) ((octet) & 0x10)
+
+/* ED137 signature */
+#define RTP_ED137_SIG 0x0067
+
+/* ED137A signature */
+#define RTP_ED137A_SIG 0x0167
+
+/* RFC 5285 one byte header signature */
+#define RTP_RFC5285_ONE_BYTE_SIG 0xBEDE
+
+/* RFC 5285 two byte header mask and signature */
+#define RTP_RFC5285_TWO_BYTE_MASK 0xFFF0
+#define RTP_RFC5285_TWO_BYTE_SIG 0x1000
+
+/* CSRC count is the last four bits */
+#define RTP_CSRC_COUNT(octet) ((octet) & 0xF)
+
+static const value_string rtp_version_vals[] =
+{
+ { 2, "RFC 1889 Version" }, /* First for speed */
+ { 0, "Old VAT Version" },
+ { 1, "First Draft Version" },
+ { 0, NULL },
+};
+
+static const range_string rtp_ext_profile_rvals[] =
+{
+ { RTP_ED137_SIG, RTP_ED137_SIG, "ED137" },
+ { RTP_ED137A_SIG, RTP_ED137A_SIG, "ED137A" },
+ { RTP_RFC5285_TWO_BYTE_SIG, RTP_RFC5285_TWO_BYTE_SIG + 0xF, "RFC 5285 Two-Byte Header Extensions" },
+ { RTP_RFC5285_ONE_BYTE_SIG, RTP_RFC5285_ONE_BYTE_SIG, "RFC 5285 One-Byte Header Extensions" },
+ { 0, 0, NULL },
+};
+
+/*
+ * Fields in the second octet of the RTP header.
+ */
+
+/* Marker is the first bit of the second octet */
+#define RTP_MARKER(octet) ((octet) & 0x80)
+
+/* Payload type is the last 7 bits */
+#define RTP_PAYLOAD_TYPE(octet) ((octet) & 0x7F)
+/* https://www.iana.org/assignments/rtp-parameters/ */
+
+#define FIRST_RTCP_CONFLICT_PAYLOAD_TYPE 64
+#define LAST_RTCP_CONFLICT_PAYLOAD_TYPE 95
+
+static const value_string rtp_payload_type_vals[] =
+{
+/* 0 */ { PT_PCMU, "ITU-T G.711 PCMU" },
+/* 1 */ { PT_1016, "USA Federal Standard FS-1016" },
+/* 2 */ { PT_G721, "ITU-T G.721" },
+/* 3 */ { PT_GSM, "GSM 06.10" },
+/* 4 */ { PT_G723, "ITU-T G.723" },
+/* 5 */ { PT_DVI4_8000, "DVI4 8000 samples/s" },
+/* 6 */ { PT_DVI4_16000, "DVI4 16000 samples/s" },
+/* 7 */ { PT_LPC, "Experimental linear predictive encoding from Xerox PARC" },
+/* 8 */ { PT_PCMA, "ITU-T G.711 PCMA" },
+/* 9 */ { PT_G722, "ITU-T G.722" },
+/* 10 */ { PT_L16_STEREO, "16-bit uncompressed audio, stereo" },
+/* 11 */ { PT_L16_MONO, "16-bit uncompressed audio, monaural" },
+/* 12 */ { PT_QCELP, "Qualcomm Code Excited Linear Predictive coding" },
+/* 13 */ { PT_CN, "Comfort noise" },
+/* 14 */ { PT_MPA, "MPEG-I/II Audio"},
+/* 15 */ { PT_G728, "ITU-T G.728" },
+/* 16 */ { PT_DVI4_11025, "DVI4 11025 samples/s" },
+/* 17 */ { PT_DVI4_22050, "DVI4 22050 samples/s" },
+/* 18 */ { PT_G729, "ITU-T G.729" },
+/* 19 */ { PT_CN_OLD, "Comfort noise (old)" },
+/* 20 */ { 20, "Unassigned" },
+/* 21 */ { 21, "Unassigned" },
+/* 22 */ { 22, "Unassigned" },
+/* 23 */ { 23, "Unassigned" },
+/* 24 */ { 24, "Unassigned" },
+/* 25 */ { PT_CELB, "Sun CellB video encoding" },
+/* 26 */ { PT_JPEG, "JPEG-compressed video" },
+/* 27 */ { 27, "Unassigned" },
+/* 28 */ { PT_NV, "'nv' program" },
+/* 29 */ { 29, "Unassigned" },
+/* 30 */ { 30, "Unassigned" },
+/* 31 */ { PT_H261, "ITU-T H.261" },
+/* 32 */ { PT_MPV, "MPEG-I/II Video"},
+/* 33 */ { PT_MP2T, "MPEG-II transport streams"},
+/* 34 */ { PT_H263, "ITU-T H.263" },
+/* 35-71 Unassigned */
+/* 35 */ { 35, "Unassigned" },
+/* 36 */ { 36, "Unassigned" },
+/* 37 */ { 37, "Unassigned" },
+/* 38 */ { 38, "Unassigned" },
+/* 39 */ { 39, "Unassigned" },
+/* 40 */ { 40, "Unassigned" },
+/* 41 */ { 41, "Unassigned" },
+/* 42 */ { 42, "Unassigned" },
+/* 43 */ { 43, "Unassigned" },
+/* 44 */ { 44, "Unassigned" },
+/* 45 */ { 45, "Unassigned" },
+/* 46 */ { 46, "Unassigned" },
+/* 47 */ { 47, "Unassigned" },
+/* 48 */ { 48, "Unassigned" },
+/* 49 */ { 49, "Unassigned" },
+/* 50 */ { 50, "Unassigned" },
+/* 51 */ { 51, "Unassigned" },
+/* 52 */ { 52, "Unassigned" },
+/* 53 */ { 53, "Unassigned" },
+/* 54 */ { 54, "Unassigned" },
+/* 55 */ { 55, "Unassigned" },
+/* 56 */ { 56, "Unassigned" },
+/* 57 */ { 57, "Unassigned" },
+/* 58 */ { 58, "Unassigned" },
+/* 59 */ { 59, "Unassigned" },
+/* 60 */ { 60, "Unassigned" },
+/* 61 */ { 61, "Unassigned" },
+/* 62 */ { 62, "Unassigned" },
+/* 63 */ { 63, "Unassigned" },
+/* 64 */ { 64, "Unassigned" },
+/* 65 */ { 65, "Unassigned" },
+/* 66 */ { 66, "Unassigned" },
+/* 67 */ { 67, "Unassigned" },
+/* 68 */ { 68, "Unassigned" },
+/* 69 */ { 69, "Unassigned" },
+/* 70 */ { 70, "Unassigned" },
+/* 71 */ { 71, "Unassigned" },
+/* 72-76 Reserved for RTCP conflict avoidance [RFC3551] */
+/* 72 */ { 72, "Reserved for RTCP conflict avoidance" },
+/* 73 */ { 73, "Reserved for RTCP conflict avoidance" },
+/* 74 */ { 74, "Reserved for RTCP conflict avoidance" },
+/* 75 */ { 75, "Reserved for RTCP conflict avoidance" },
+/* 76 */ { 76, "Reserved for RTCP conflict avoidance" },
+/* 77-95 Unassigned, MAY be used if > 32 PT are used */
+/* 77 */ { 77, "Unassigned" },
+/* 78 */ { 78, "Unassigned" },
+/* 79 */ { 79, "Unassigned" },
+/* 80 */ { 80, "Unassigned" },
+/* 81 */ { 81, "Unassigned" },
+/* 82 */ { 82, "Unassigned" },
+/* 83 */ { 83, "Unassigned" },
+/* 84 */ { 84, "Unassigned" },
+/* 85 */ { 85, "Unassigned" },
+/* 86 */ { 86, "Unassigned" },
+/* 87 */ { 87, "Unassigned" },
+/* 88 */ { 88, "Unassigned" },
+/* 89 */ { 89, "Unassigned" },
+/* 90 */ { 90, "Unassigned" },
+/* 91 */ { 91, "Unassigned" },
+/* 92 */ { 92, "Unassigned" },
+/* 93 */ { 93, "Unassigned" },
+/* 94 */ { 94, "Unassigned" },
+/* 95 */ { 95, "Unassigned" },
+ /* Added to support additional RTP payload types
+ * See epan/rtp_pt.h */
+ { PT_UNDF_96, "DynamicRTP-Type-96" },
+ { PT_UNDF_97, "DynamicRTP-Type-97" },
+ { PT_UNDF_98, "DynamicRTP-Type-98" },
+ { PT_UNDF_99, "DynamicRTP-Type-99" },
+ { PT_UNDF_100, "DynamicRTP-Type-100" },
+ { PT_UNDF_101, "DynamicRTP-Type-101" },
+ { PT_UNDF_102, "DynamicRTP-Type-102" },
+ { PT_UNDF_103, "DynamicRTP-Type-103" },
+ { PT_UNDF_104, "DynamicRTP-Type-104" },
+ { PT_UNDF_105, "DynamicRTP-Type-105" },
+ { PT_UNDF_106, "DynamicRTP-Type-106" },
+ { PT_UNDF_107, "DynamicRTP-Type-107" },
+ { PT_UNDF_108, "DynamicRTP-Type-108" },
+ { PT_UNDF_109, "DynamicRTP-Type-109" },
+ { PT_UNDF_110, "DynamicRTP-Type-110" },
+ { PT_UNDF_111, "DynamicRTP-Type-111" },
+ { PT_UNDF_112, "DynamicRTP-Type-112" },
+ { PT_UNDF_113, "DynamicRTP-Type-113" },
+ { PT_UNDF_114, "DynamicRTP-Type-114" },
+ { PT_UNDF_115, "DynamicRTP-Type-115" },
+ { PT_UNDF_116, "DynamicRTP-Type-116" },
+ { PT_UNDF_117, "DynamicRTP-Type-117" },
+ { PT_UNDF_118, "DynamicRTP-Type-118" },
+ { PT_UNDF_119, "DynamicRTP-Type-119" },
+ { PT_UNDF_120, "DynamicRTP-Type-120" },
+ { PT_UNDF_121, "DynamicRTP-Type-121" },
+ { PT_UNDF_122, "DynamicRTP-Type-122" },
+ { PT_UNDF_123, "DynamicRTP-Type-123" },
+ { PT_UNDF_124, "DynamicRTP-Type-124" },
+ { PT_UNDF_125, "DynamicRTP-Type-125" },
+ { PT_UNDF_126, "DynamicRTP-Type-126" },
+ { PT_UNDF_127, "DynamicRTP-Type-127" },
+
+ { 0, NULL },
+};
+
+value_string_ext rtp_payload_type_vals_ext = VALUE_STRING_EXT_INIT(rtp_payload_type_vals);
+
+static const value_string rtp_payload_type_short_vals[] =
+{
+ { PT_PCMU, "g711U" },
+ { PT_1016, "fs-1016" },
+ { PT_G721, "g721" },
+ { PT_GSM, "GSM" },
+ { PT_G723, "g723" },
+ { PT_DVI4_8000, "DVI4 8k" },
+ { PT_DVI4_16000, "DVI4 16k" },
+ { PT_LPC, "Exp. from Xerox PARC" },
+ { PT_PCMA, "g711A" },
+ { PT_G722, "g722" },
+ { PT_L16_STEREO, "16-bit audio, stereo" },
+ { PT_L16_MONO, "16-bit audio, monaural" },
+ { PT_QCELP, "Qualcomm" },
+ { PT_CN, "CN" },
+ { PT_MPA, "MPEG-I/II Audio"},
+ { PT_G728, "g728" },
+ { PT_DVI4_11025, "DVI4 11k" },
+ { PT_DVI4_22050, "DVI4 22k" },
+ { PT_G729, "g729" },
+ { PT_CN_OLD, "CN(old)" },
+ { 20, "Unassigned" },
+ { 21, "Unassigned" },
+ { 22, "Unassigned" },
+ { 23, "Unassigned" },
+ { 24, "Unassigned" },
+ { PT_CELB, "CellB" },
+ { PT_JPEG, "JPEG" },
+ { 27, "Unassigned" },
+ { PT_NV, "NV" },
+ { 29, "Unassigned" },
+ { 30, "Unassigned" },
+ { PT_H261, "h261" },
+ { PT_MPV, "MPEG-I/II Video"},
+ { PT_MP2T, "MPEG-II streams"},
+ { PT_H263, "h263" },
+/* 35-71 Unassigned */
+ { 35, "Unassigned" },
+ { 36, "Unassigned" },
+ { 37, "Unassigned" },
+ { 38, "Unassigned" },
+ { 39, "Unassigned" },
+ { 40, "Unassigned" },
+ { 41, "Unassigned" },
+ { 42, "Unassigned" },
+ { 43, "Unassigned" },
+ { 44, "Unassigned" },
+ { 45, "Unassigned" },
+ { 46, "Unassigned" },
+ { 47, "Unassigned" },
+ { 48, "Unassigned" },
+ { 49, "Unassigned" },
+ { 50, "Unassigned" },
+ { 51, "Unassigned" },
+ { 52, "Unassigned" },
+ { 53, "Unassigned" },
+ { 54, "Unassigned" },
+ { 55, "Unassigned" },
+ { 56, "Unassigned" },
+ { 57, "Unassigned" },
+ { 58, "Unassigned" },
+ { 59, "Unassigned" },
+ { 60, "Unassigned" },
+ { 61, "Unassigned" },
+ { 62, "Unassigned" },
+ { 63, "Unassigned" },
+ { 64, "Unassigned" },
+ { 65, "Unassigned" },
+ { 66, "Unassigned" },
+ { 67, "Unassigned" },
+ { 68, "Unassigned" },
+ { 69, "Unassigned" },
+ { 70, "Unassigned" },
+ { 71, "Unassigned" },
+/* 72-76 Reserved for RTCP conflict avoidance - [RFC3551] */
+ { 72, "Reserved for RTCP conflict avoidance" },
+ { 73, "Reserved for RTCP conflict avoidance" },
+ { 74, "Reserved for RTCP conflict avoidance" },
+ { 75, "Reserved for RTCP conflict avoidance" },
+ { 76, "Reserved for RTCP conflict avoidance" },
+/* 77-95 Unassigned, MAY be used if > 32 PT are used */
+ { 77, "Unassigned" },
+ { 78, "Unassigned" },
+ { 79, "Unassigned" },
+ { 80, "Unassigned" },
+ { 81, "Unassigned" },
+ { 82, "Unassigned" },
+ { 83, "Unassigned" },
+ { 84, "Unassigned" },
+ { 85, "Unassigned" },
+ { 86, "Unassigned" },
+ { 87, "Unassigned" },
+ { 88, "Unassigned" },
+ { 89, "Unassigned" },
+ { 90, "Unassigned" },
+ { 91, "Unassigned" },
+ { 92, "Unassigned" },
+ { 93, "Unassigned" },
+ { 94, "Unassigned" },
+ { 95, "Unassigned" },
+ /* Short RTP types */
+ { PT_UNDF_96, "RTPType-96" },
+ { PT_UNDF_97, "RTPType-97" },
+ { PT_UNDF_98, "RTPType-98" },
+ { PT_UNDF_99, "RTPType-99" },
+ { PT_UNDF_100, "RTPType-100" },
+ { PT_UNDF_101, "RTPType-101" },
+ { PT_UNDF_102, "RTPType-102" },
+ { PT_UNDF_103, "RTPType-103" },
+ { PT_UNDF_104, "RTPType-104" },
+ { PT_UNDF_105, "RTPType-105" },
+ { PT_UNDF_106, "RTPType-106" },
+ { PT_UNDF_107, "RTPType-107" },
+ { PT_UNDF_108, "RTPType-108" },
+ { PT_UNDF_109, "RTPType-109" },
+ { PT_UNDF_110, "RTPType-110" },
+ { PT_UNDF_111, "RTPType-111" },
+ { PT_UNDF_112, "RTPType-112" },
+ { PT_UNDF_113, "RTPType-113" },
+ { PT_UNDF_114, "RTPType-114" },
+ { PT_UNDF_115, "RTPType-115" },
+ { PT_UNDF_116, "RTPType-116" },
+ { PT_UNDF_117, "RTPType-117" },
+ { PT_UNDF_118, "RTPType-118" },
+ { PT_UNDF_119, "RTPType-119" },
+ { PT_UNDF_120, "RTPType-120" },
+ { PT_UNDF_121, "RTPType-121" },
+ { PT_UNDF_122, "RTPType-122" },
+ { PT_UNDF_123, "RTPType-123" },
+ { PT_UNDF_124, "RTPType-124" },
+ { PT_UNDF_125, "RTPType-125" },
+ { PT_UNDF_126, "RTPType-126" },
+ { PT_UNDF_127, "RTPType-127" },
+
+ { 0, NULL },
+};
+value_string_ext rtp_payload_type_short_vals_ext = VALUE_STRING_EXT_INIT(rtp_payload_type_short_vals);
+
+#if 0
+static const value_string srtp_encryption_alg_vals[] =
+{
+ { SRTP_ENC_ALG_NULL, "Null Encryption" },
+ { SRTP_ENC_ALG_AES_CM, "AES-128 Counter Mode" },
+ { SRTP_ENC_ALG_AES_F8, "AES-128 F8 Mode" },
+ { 0, NULL },
+};
+
+static const value_string srtp_auth_alg_vals[] =
+{
+ { SRTP_AUTH_ALG_NONE, "No Authentication" },
+ { SRTP_AUTH_ALG_HMAC_SHA1, "HMAC-SHA1" },
+ { 0, NULL },
+};
+#endif
+
+static void rtp_prompt(packet_info *pinfo _U_, gchar* result)
+{
+ guint payload_type = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_rtp, RTP_DECODE_AS_PROTO_DATA));
+
+ /* Dynamic payload range, don't expose value as it may change within conversation */
+ if (payload_type > 95)
+ {
+ snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "RTP payload type as");
+ }
+ else
+ {
+ snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "RTP payload type %d as", payload_type);
+ }
+}
+
+static gpointer rtp_value(packet_info *pinfo)
+{
+ guint payload_type = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_rtp, RTP_DECODE_AS_PROTO_DATA));
+
+ return GUINT_TO_POINTER(payload_type);
+}
+
+#ifdef DEBUG_CONVERSATION
+/* Called for each entry in the rtp_dyn_payload hash table. */
+static void
+rtp_dyn_payload_table_foreach_func(gpointer key, gpointer value, gpointer user_data _U_) {
+ guint pt = GPOINTER_TO_UINT(key);
+ encoding_name_and_rate_t *encoding = (encoding_name_and_rate_t*) value;
+
+ DPRINT2(("pt=%d", pt));
+ if (encoding) {
+ DPRINT2(("encoding_name=%s",
+ encoding->encoding_name ? encoding->encoding_name : "NULL"));
+ DPRINT2(("sample_rate=%d", encoding->sample_rate));
+ DPRINT2(("channels=%u", encoding->channels));
+ } else {
+ DPRINT2(("encoding=NULL"));
+ }
+}
+
+void
+rtp_dump_dyn_payload(rtp_dyn_payload_t *rtp_dyn_payload) {
+ DPRINT2(("rtp_dyn_payload hash table contents:"));
+ DINDENT();
+ if (!rtp_dyn_payload) {
+ DPRINT2(("null pointer to rtp_dyn_payload"));
+ DENDENT();
+ return;
+ }
+ DPRINT2(("ref_count=%zu", rtp_dyn_payload->ref_count));
+ if (!rtp_dyn_payload->table) {
+ DPRINT2(("null rtp_dyn_payload table"));
+ DENDENT();
+ return;
+ }
+ if (g_hash_table_size(rtp_dyn_payload->table) == 0) {
+ DPRINT2(("rtp_dyn_payload has no entries"));
+ } else {
+ g_hash_table_foreach(rtp_dyn_payload->table, rtp_dyn_payload_table_foreach_func, NULL);
+ }
+ DENDENT();
+}
+#endif /* DEBUG_CONVERSATION */
+
+/* A single hash table to hold pointers to all the rtp_dyn_payload_t's we create/destroy.
+ This is necessary because we need to g_hash_table_destroy() them, either individually or
+ all at once at the end of the wmem file scope. Since rtp_dyn_payload_free() removes them
+ individually, we need to remove those then; and when the file scope is over, we have a
+ single registered callback walk this GHashTable and destroy each member as well as this
+ GHashTable.
+ */
+static GHashTable *rtp_dyn_payloads = NULL;
+
+static gboolean
+fmtp_free(gpointer key, gpointer value, gpointer user_data)
+{
+ wmem_allocator_t *scope = (wmem_allocator_t*)user_data;
+
+ wmem_free(scope, key);
+ wmem_free(scope, value);
+
+ return TRUE;
+}
+
+/* the following is the GDestroyNotify function used when the individual rtp_dyn_payload_t
+ GHashTables are destroyed */
+static void
+rtp_dyn_payload_value_destroy(gpointer data)
+{
+ encoding_name_and_rate_t *encoding_name_and_rate_pt = (encoding_name_and_rate_t*) data;
+ wmem_free(wmem_file_scope(), encoding_name_and_rate_pt->encoding_name);
+ wmem_map_foreach_remove(encoding_name_and_rate_pt->fmtp_map, fmtp_free, wmem_file_scope());
+ wmem_free(wmem_file_scope(), encoding_name_and_rate_pt->fmtp_map);
+ wmem_free(wmem_file_scope(), encoding_name_and_rate_pt);
+}
+
+/* this gets called by wmem_rtp_dyn_payload_destroy_cb */
+static gboolean
+rtp_dyn_payloads_table_steal_func(gpointer key _U_, gpointer value, gpointer user_data _U_)
+{
+ rtp_dyn_payload_t *rtp_dyn_payload = (rtp_dyn_payload_t *)value;
+
+#ifdef DEBUG_CONVERSATION
+ DPRINT(("about to steal_all and destroy the following:"));
+ DINDENT();
+ rtp_dump_dyn_payload(rtp_dyn_payload);
+ DENDENT();
+#endif
+
+ if (rtp_dyn_payload->ref_count == 0) {
+ /* this shouldn't happen */
+ DPRINT(("rtp_dyn_payload cannot be free'd because it should already have been!\n"));
+ }
+ else if (rtp_dyn_payload->table) {
+ /* each member was created with a wmem file scope, so there's no point in calling the
+ destroy functions for the GHashTable entries, so we steal them instead */
+ g_hash_table_steal_all(rtp_dyn_payload->table);
+ g_hash_table_destroy(rtp_dyn_payload->table);
+ }
+
+ return TRUE;
+}
+
+/* the following is used as the wmem callback to destroy *all* alive rtp_dyn_payload_t's,
+ which are pointed to by the single rtp_dyn_payloads GHashTable above.
+ */
+static bool
+wmem_rtp_dyn_payload_destroy_cb(wmem_allocator_t *allocator _U_, wmem_cb_event_t event _U_,
+ void *user_data _U_)
+{
+ DPRINT(("destroying %u remaining rtp_dyn_payload_t's", g_hash_table_size(rtp_dyn_payloads)));
+
+ /* each member was created with a wmem file scope, so there's no point in calling the
+ destroy functions for the GHashTable entries, so we steal them instead */
+ g_hash_table_foreach_steal(rtp_dyn_payloads, rtp_dyn_payloads_table_steal_func, NULL);
+ g_hash_table_destroy(rtp_dyn_payloads);
+ rtp_dyn_payloads = NULL;
+
+ /* remove this callback? */
+ return FALSE;
+}
+
+/* the following initializes the single GHashTable - this is invoked as an init_routine,
+ but those are called both at init and cleanup times, and the cleanup time is before
+ wmem scope is exited, so we ignore this if rtp_dyn_payloads is not NULL.
+ */
+static void
+rtp_dyn_payloads_init(void)
+{
+ if (rtp_dyn_payloads == NULL) {
+ rtp_dyn_payloads = g_hash_table_new(NULL, NULL);
+ wmem_register_callback(wmem_file_scope(), wmem_rtp_dyn_payload_destroy_cb, NULL);
+ }
+}
+
+/* creates a new hashtable and sets ref_count to 1, returning the newly created object */
+rtp_dyn_payload_t* rtp_dyn_payload_new(void)
+{
+ /* create the new entry */
+ rtp_dyn_payload_t * rtp_dyn_payload = wmem_new(wmem_file_scope(), rtp_dyn_payload_t);
+ rtp_dyn_payload->table = g_hash_table_new_full(NULL, NULL, NULL, rtp_dyn_payload_value_destroy);
+ rtp_dyn_payload->ref_count = 1;
+
+ /* now put it in our single rtp_dyn_payloads GHashTable */
+ g_hash_table_insert(rtp_dyn_payloads, rtp_dyn_payload, rtp_dyn_payload);
+
+ return rtp_dyn_payload;
+}
+
+/* Creates a copy of the given dynamic payload information. */
+rtp_dyn_payload_t* rtp_dyn_payload_dup(rtp_dyn_payload_t *rtp_dyn_payload)
+{
+ rtp_dyn_payload_t *rtp_dyn_payload2 = rtp_dyn_payload_new();
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_hash_table_iter_init(&iter, rtp_dyn_payload->table);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ const guint pt = GPOINTER_TO_UINT(key);
+ encoding_name_and_rate_t *encoding_name_and_rate_pt =
+ (encoding_name_and_rate_t *)value;
+
+ rtp_dyn_payload_insert_full(rtp_dyn_payload2, pt,
+ encoding_name_and_rate_pt->encoding_name,
+ encoding_name_and_rate_pt->sample_rate,
+ encoding_name_and_rate_pt->channels,
+ encoding_name_and_rate_pt->fmtp_map);
+
+ }
+
+ return rtp_dyn_payload2;
+}
+
+static rtp_dyn_payload_t*
+rtp_dyn_payload_ref(rtp_dyn_payload_t *rtp_dyn_payload)
+{
+ if (rtp_dyn_payload) {
+ rtp_dyn_payload->ref_count++;
+ }
+ return rtp_dyn_payload;
+}
+
+static void
+rtp_dyn_payload_add_fmtp_int(gpointer key, gpointer value, gpointer user_data)
+{
+ wmem_map_t *fmtp_map = (wmem_map_t*)user_data;
+ const char *k = (const char*)key;
+ const char *v = (const char*)value;
+
+ wmem_map_insert(fmtp_map, wmem_strdup(wmem_file_scope(), k), wmem_strdup(wmem_file_scope(), v));
+}
+
+/* Inserts the given payload type key, for the encoding name and sample rate,
+ into the hash table. Copy all the format parameters in the map given into
+ the format parameter map for the new entry.
+ This makes copies of the encoding name and the format parameters, scoped to
+ the life of the capture file or sooner if rtp_dyn_payload_free is called.
+ */
+void
+rtp_dyn_payload_insert_full(rtp_dyn_payload_t *rtp_dyn_payload,
+ const guint pt,
+ const gchar* encoding_name,
+ const int sample_rate,
+ const unsigned channels,
+ wmem_map_t *fmtp_map)
+{
+ if (rtp_dyn_payload && rtp_dyn_payload->table) {
+ encoding_name_and_rate_t *encoding_name_and_rate_pt = (encoding_name_and_rate_t*)g_hash_table_lookup(rtp_dyn_payload->table,
+ GUINT_TO_POINTER(pt));
+ if (!encoding_name_and_rate_pt) {
+ encoding_name_and_rate_pt = wmem_new(wmem_file_scope(), encoding_name_and_rate_t);
+ encoding_name_and_rate_pt->fmtp_map = wmem_map_new(wmem_file_scope(), wmem_str_hash, g_str_equal);
+ g_hash_table_insert(rtp_dyn_payload->table, GUINT_TO_POINTER(pt), encoding_name_and_rate_pt);
+ }
+ encoding_name_and_rate_pt->encoding_name = wmem_strdup(wmem_file_scope(), encoding_name);
+ encoding_name_and_rate_pt->sample_rate = sample_rate;
+ encoding_name_and_rate_pt->channels = channels;
+ if (fmtp_map) {
+ wmem_map_foreach(fmtp_map, rtp_dyn_payload_add_fmtp_int, encoding_name_and_rate_pt->fmtp_map);
+ }
+ }
+}
+
+/* Inserts the given payload type key, for the encoding name and sample rate,
+ into the hash table.
+ This makes copies of the encoding name, scoped to the life of the capture
+ file or sooner if rtp_dyn_payload_free is called. */
+void
+rtp_dyn_payload_insert(rtp_dyn_payload_t *rtp_dyn_payload,
+ const guint pt,
+ const gchar* encoding_name,
+ const int sample_rate,
+ const unsigned channels)
+{
+ rtp_dyn_payload_insert_full(rtp_dyn_payload, pt, encoding_name, sample_rate, channels, NULL);
+}
+
+/* Adds the given format parameter to the fmtp_map for the given payload type
+ in the RTP dynamic payload hashtable, if that payload type has been
+ inserted with rtp_dyn_payload_insert. The format parameter name and value
+ are copied, with scope the lifetime of the capture file.
+ */
+void
+rtp_dyn_payload_add_fmtp(rtp_dyn_payload_t *rtp_dyn_payload,
+ const guint pt,
+ const char *key, const char *value)
+{
+ if (rtp_dyn_payload && rtp_dyn_payload->table) {
+ encoding_name_and_rate_t *encoding_name_and_rate_pt = (encoding_name_and_rate_t*)g_hash_table_lookup(rtp_dyn_payload->table,
+ GUINT_TO_POINTER(pt));
+
+ if (!encoding_name_and_rate_pt) {
+ rtp_dyn_payload_insert(rtp_dyn_payload, pt, "Unknown", 0, 1);
+ encoding_name_and_rate_pt = (encoding_name_and_rate_t*)g_hash_table_lookup(rtp_dyn_payload->table, GUINT_TO_POINTER(pt));
+ }
+
+ rtp_dyn_payload_add_fmtp_int((void*)key, (void*)value, encoding_name_and_rate_pt->fmtp_map);
+ }
+}
+
+/* Replaces the given payload type key in the hash table, with the encoding name and sample rate.
+ This makes copies of the encoding name, scoped to the life of the capture file or sooner if
+ rtp_dyn_payload_free is called. */
+/* Not used anymore
+void
+rtp_dyn_payload_replace(rtp_dyn_payload_t *rtp_dyn_payload,
+ const guint pt,
+ const gchar* encoding_name,
+ const int sample_rate)
+{
+ if (rtp_dyn_payload && rtp_dyn_payload->table) {
+ encoding_name_and_rate_t *encoding_name_and_rate_pt =
+ wmem_new(wmem_file_scope(), encoding_name_and_rate_t);
+ encoding_name_and_rate_pt->encoding_name = wmem_strdup(wmem_file_scope(), encoding_name);
+ encoding_name_and_rate_pt->sample_rate = sample_rate;
+ g_hash_table_replace(rtp_dyn_payload->table, GUINT_TO_POINTER(pt), encoding_name_and_rate_pt);
+ }
+}
+*/
+
+/* removes the given payload type */
+/* Not used anymore
+gboolean
+rtp_dyn_payload_remove(rtp_dyn_payload_t *rtp_dyn_payload, const guint pt)
+{
+ return (rtp_dyn_payload && rtp_dyn_payload->table &&
+ g_hash_table_remove(rtp_dyn_payload->table, GUINT_TO_POINTER(pt)));
+}
+*/
+
+/* retrieves the encoding name for the given payload type */
+const gchar*
+rtp_dyn_payload_get_name(rtp_dyn_payload_t *rtp_dyn_payload, const guint pt)
+{
+ encoding_name_and_rate_t *encoding_name_and_rate_pt;
+
+ if (!rtp_dyn_payload || !rtp_dyn_payload->table) return NULL;
+
+ encoding_name_and_rate_pt = (encoding_name_and_rate_t*)g_hash_table_lookup(rtp_dyn_payload->table,
+ GUINT_TO_POINTER(pt));
+
+ return (encoding_name_and_rate_pt ? encoding_name_and_rate_pt->encoding_name : NULL);
+}
+
+/*
+ Retrieves the encoding name, sample rate, and format parameters map for the
+ given payload type. The encoding string pointed to is only valid until
+ the entry is replaced, removed, or the hash table is destroyed, so duplicate
+ it if you need it long. Each of the three output parameters are optional and
+ can be NULL.
+ */
+gboolean
+rtp_dyn_payload_get_full(rtp_dyn_payload_t *rtp_dyn_payload, const guint pt,
+ const gchar **encoding_name, int *sample_rate,
+ unsigned *channels, wmem_map_t **fmtp_map)
+{
+ encoding_name_and_rate_t *encoding_name_and_rate_pt;
+ if (encoding_name) {
+ *encoding_name = NULL;
+ }
+ if (sample_rate) {
+ *sample_rate = 0;
+ }
+ if (channels) {
+ *channels = 0;
+ }
+ if (fmtp_map) {
+ *fmtp_map = NULL;
+ }
+
+ if (!rtp_dyn_payload || !rtp_dyn_payload->table) return FALSE;
+
+ encoding_name_and_rate_pt = (encoding_name_and_rate_t*)g_hash_table_lookup(rtp_dyn_payload->table,
+ GUINT_TO_POINTER(pt));
+
+ if (encoding_name_and_rate_pt) {
+ if (encoding_name) {
+ *encoding_name = encoding_name_and_rate_pt->encoding_name;
+ }
+ if (sample_rate) {
+ *sample_rate = encoding_name_and_rate_pt->sample_rate;
+ }
+ if (channels) {
+ *channels = encoding_name_and_rate_pt->channels;
+ }
+ if (fmtp_map) {
+ *fmtp_map = encoding_name_and_rate_pt->fmtp_map;
+ }
+ }
+
+ return (encoding_name_and_rate_pt != NULL);
+}
+
+/* Free's and destroys the dyn_payload hash table; internally this decrements the ref_count
+ and only free's it if the ref_count == 0. */
+void
+rtp_dyn_payload_free(rtp_dyn_payload_t *rtp_dyn_payload)
+{
+ if (!rtp_dyn_payload) return;
+
+ if (rtp_dyn_payload->ref_count > 0)
+ --(rtp_dyn_payload->ref_count);
+
+ if (rtp_dyn_payload->ref_count == 0) {
+
+#ifdef DEBUG_CONVERSATION
+ DPRINT(("free'ing the following rtp_dyn_payload:"));
+ DINDENT();
+ rtp_dump_dyn_payload(rtp_dyn_payload);
+ DENDENT();
+#endif
+
+ /* remove it from the single rtp_dyn_payloads GHashTable */
+ if (!g_hash_table_remove(rtp_dyn_payloads, rtp_dyn_payload)) {
+ DPRINT(("rtp_dyn_payload not found in rtp_dyn_payloads table to remove!"));
+ }
+
+ /* destroy the table GHashTable in it - this automatically deletes the
+ members too, because we used destroy function callbacks */
+ if (rtp_dyn_payload->table)
+ g_hash_table_destroy(rtp_dyn_payload->table);
+
+ /* free the object itself */
+ wmem_free(wmem_file_scope(), rtp_dyn_payload);
+ }
+}
+
+void
+bluetooth_add_address(packet_info *pinfo, address *addr, guint32 stream_number,
+ const gchar *setup_method, guint32 setup_frame_number,
+ guint32 media_types, void *data)
+{
+ address null_addr;
+ conversation_t* p_conv;
+ struct _rtp_conversation_info *p_conv_data = NULL;
+ /*
+ * If this isn't the first time this packet has been processed,
+ * we've already done this work, so we don't need to do it
+ * again.
+ */
+ if ((pinfo->fd->visited) || (rtp_handle == NULL))
+ {
+ return;
+ }
+
+ clear_address(&null_addr);
+
+ /*
+ * Check if the ip address and port combination is not
+ * already registered as a conversation.
+ */
+ p_conv = find_conversation(setup_frame_number, addr, &null_addr, CONVERSATION_BLUETOOTH, stream_number, stream_number,
+ NO_ADDR_B | NO_PORT_B);
+
+ /*
+ * If not, create a new conversation.
+ */
+ if (!p_conv || p_conv->setup_frame != setup_frame_number) {
+ p_conv = conversation_new(setup_frame_number, addr, &null_addr, CONVERSATION_BLUETOOTH, stream_number, stream_number,
+ NO_ADDR2 | NO_PORT2);
+ }
+
+ /* Set dissector */
+ conversation_set_dissector(p_conv, rtp_handle);
+
+ /*
+ * Check if the conversation has data associated with it.
+ */
+ p_conv_data = (struct _rtp_conversation_info *)conversation_get_proto_data(p_conv, proto_rtp);
+
+ /*
+ * If not, add a new data item.
+ */
+ if (! p_conv_data) {
+ /* Create conversation data */
+ p_conv_data = wmem_new0(wmem_file_scope(), struct _rtp_conversation_info);
+
+ p_conv_data->ssrc_number_space = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
+ p_conv_data->rtp_conv_info = wmem_new(wmem_file_scope(), rtp_private_conv_info);
+ p_conv_data->rtp_conv_info->multisegment_pdus = wmem_tree_new(wmem_file_scope());
+ conversation_add_proto_data(p_conv, proto_rtp, p_conv_data);
+
+ if (media_types == RTP_MEDIA_AUDIO) {
+ p_conv_data->bta2dp_info = (bta2dp_codec_info_t *) wmem_memdup(wmem_file_scope(), data, sizeof(bta2dp_codec_info_t));
+ } else if (media_types == RTP_MEDIA_VIDEO) {
+ p_conv_data->btvdp_info = (btvdp_codec_info_t *) wmem_memdup(wmem_file_scope(), data, sizeof(btvdp_codec_info_t));
+ }
+ }
+
+ /*
+ * Update the conversation data.
+ */
+ /* Free the hash if already exists */
+ rtp_dyn_payload_free(p_conv_data->rtp_dyn_payload);
+
+ (void) g_strlcpy(p_conv_data->method, setup_method, MAX_RTP_SETUP_METHOD_SIZE+1);
+ p_conv_data->frame_number = setup_frame_number;
+ p_conv_data->media_types = media_types;
+ p_conv_data->rtp_dyn_payload = NULL;
+ p_conv_data->srtp_info = NULL;
+}
+static void
+rtp_add_setup_info_if_no_duplicate(sdp_setup_info_t *setup_info, wmem_array_t *sdp_conv_info_list)
+{
+ sdp_setup_info_t *stored_setup_info;
+ guint i;
+
+ for (i = 0; i < wmem_array_get_count(sdp_conv_info_list); i++) {
+ stored_setup_info = (sdp_setup_info_t *)wmem_array_index(sdp_conv_info_list, i);
+
+ /* Check if we have the call id allready */
+ if ((stored_setup_info->hf_type == SDP_TRACE_ID_HF_TYPE_STR) && (setup_info->hf_type == SDP_TRACE_ID_HF_TYPE_STR)) {
+ if (strcmp(stored_setup_info->trace_id.str, setup_info->trace_id.str) == 0) {
+ return; /* Do not store the call id */
+ }
+ } else if ((stored_setup_info->hf_type == SDP_TRACE_ID_HF_TYPE_GUINT32) && (setup_info->hf_type == SDP_TRACE_ID_HF_TYPE_GUINT32)) {
+ if (stored_setup_info->trace_id.num == setup_info->trace_id.num) {
+ return; /* Do not store the call id */
+ }
+ }
+ }
+
+ wmem_array_append(sdp_conv_info_list, setup_info, 1);
+
+}
+/* Set up an SRTP conversation */
+void
+srtp_add_address(packet_info *pinfo, const port_type ptype, address *addr, int port, int other_port,
+ const gchar *setup_method, guint32 setup_frame_number,
+ guint32 media_types _U_, rtp_dyn_payload_t *rtp_dyn_payload,
+ struct srtp_info *srtp_info, sdp_setup_info_t *setup_info)
+{
+ address null_addr;
+ conversation_t* p_conv, *sdp_conv;
+ struct _rtp_conversation_info *p_conv_data;
+ wmem_array_t *rtp_conv_info_list = NULL;
+
+ /*
+ * If this isn't the first time this packet has been processed,
+ * we've already done this work, so we don't need to do it
+ * again.
+ */
+ if ((pinfo->fd->visited) || (rtp_handle == NULL) || (rtp_rfc4571_handle == NULL))
+ {
+ return;
+ }
+
+ DPRINT(("#%u: %srtp_add_address(%d, %s, %u, %u, %s, %u)",
+ pinfo->num, (srtp_info)?"s":"", ptype, address_to_str(pinfo->pool, addr), port,
+ other_port, setup_method, setup_frame_number));
+ DINDENT();
+
+ clear_address(&null_addr);
+
+ /*
+ * Check if the ip address and port combination is not
+ * already registered as a conversation.
+ */
+ p_conv = find_conversation(setup_frame_number, addr, &null_addr, conversation_pt_to_conversation_type(ptype), port, other_port,
+ NO_ADDR_B | (!other_port ? NO_PORT_B : 0));
+
+ if (p_conv) {
+ /*
+ * Check if the conversation has data associated with it.
+ */
+ p_conv_data = (struct _rtp_conversation_info *)conversation_get_proto_data(p_conv, proto_rtp);
+ if (p_conv_data) {
+ rtp_conv_info_list = p_conv_data->rtp_sdp_setup_info_list;
+ }
+ }
+
+ DENDENT();
+ DPRINT(("did %sfind conversation", p_conv?"":"NOT "));
+
+ /*
+ * If not, create a new conversation.
+ */
+ if (!p_conv || p_conv->setup_frame != setup_frame_number) {
+ p_conv = conversation_new(setup_frame_number, addr, &null_addr, conversation_pt_to_conversation_type(ptype),
+ (guint32)port, (guint32)other_port,
+ NO_ADDR2 | (!other_port ? NO_PORT2 : 0));
+ }
+
+ /* Set dissector */
+ if (ptype == PT_UDP) {
+ /* For RFC 5761 multiplexing, go ahead and create/update [S]RTCP
+ * info for the conversation, since this dissector will pass RTCP PTs
+ * to the RTCP dissector anyway.
+ * XXX: We only do this on UDP, as RFC 4571 specifies RTP and RTCP on
+ * different ports, but the RTCP dissector (like SDP) doesn't support
+ * RFC 4571 currently anyway.
+ */
+ srtcp_add_address(pinfo, addr, port, other_port, setup_method, setup_frame_number, srtp_info);
+ /* Set the dissector afterwards, since RTCP will set the conversation
+ * to its dissector, but packets should go to RTP first.
+ */
+ conversation_set_dissector(p_conv, rtp_handle);
+ } else if (ptype == PT_TCP) {
+ conversation_set_dissector(p_conv, rtp_rfc4571_handle);
+ } else {
+ DISSECTOR_ASSERT(FALSE);
+ }
+
+ /*
+ * Check if the conversation has data associated with it.
+ */
+ p_conv_data = (struct _rtp_conversation_info *)conversation_get_proto_data(p_conv, proto_rtp);
+
+ /*
+ * If not, add a new data item.
+ */
+ if (! p_conv_data) {
+ DPRINT(("creating new conversation data"));
+
+ /* Create conversation data */
+ p_conv_data = wmem_new0(wmem_file_scope(), struct _rtp_conversation_info);
+
+ p_conv_data->ssrc_number_space = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
+ p_conv_data->rtp_conv_info = wmem_new(wmem_file_scope(), rtp_private_conv_info);
+ p_conv_data->rtp_conv_info->multisegment_pdus = wmem_tree_new(wmem_file_scope());
+ DINDENT();
+ conversation_add_proto_data(p_conv, proto_rtp, p_conv_data);
+ DENDENT();
+ }
+#ifdef DEBUG_CONVERSATION
+ else {
+ DPRINT(("conversation already exists"));
+ }
+#endif
+
+ /*
+ * Update the conversation data.
+ */
+ /* Free the hash if a different one already exists */
+ if (p_conv_data->rtp_dyn_payload != rtp_dyn_payload) {
+ rtp_dyn_payload_free(p_conv_data->rtp_dyn_payload);
+ p_conv_data->rtp_dyn_payload = rtp_dyn_payload_ref(rtp_dyn_payload);
+ } else {
+ DPRINT(("passed-in rtp_dyn_payload is the same as in the conversation"));
+ }
+
+ (void) g_strlcpy(p_conv_data->method, setup_method, MAX_RTP_SETUP_METHOD_SIZE+1);
+ p_conv_data->frame_number = setup_frame_number;
+ p_conv_data->media_types = media_types;
+ p_conv_data->srtp_info = srtp_info;
+ p_conv_data->bta2dp_info = NULL;
+ p_conv_data->btvdp_info = NULL;
+
+ /* If we had a sdp setup info list put it back in the potentially new conversation*/
+ p_conv_data->rtp_sdp_setup_info_list = rtp_conv_info_list;
+ if (setup_info) {
+ /* If we have new setup info add it to the list*/
+ if (p_conv_data->rtp_sdp_setup_info_list) {
+ /* Add info to the SDP conversation */
+ rtp_add_setup_info_if_no_duplicate(setup_info, p_conv_data->rtp_sdp_setup_info_list);
+ } else {
+ p_conv_data->rtp_sdp_setup_info_list = wmem_array_new(wmem_file_scope(), sizeof(sdp_setup_info_t));
+ wmem_array_append(p_conv_data->rtp_sdp_setup_info_list, setup_info, 1);
+ }
+ }
+ sdp_conv = find_or_create_conversation(pinfo);
+ if (sdp_conv && p_conv_data->rtp_sdp_setup_info_list) {
+ /* Add the collected information to the SDP conversation */
+ conversation_add_proto_data(sdp_conv, proto_sdp, p_conv_data->rtp_sdp_setup_info_list);
+ }
+
+}
+
+/* Set up an RTP conversation */
+void
+rtp_add_address(packet_info *pinfo, const port_type ptype, address *addr, int port, int other_port,
+ const gchar *setup_method, guint32 setup_frame_number,
+ guint32 media_types , rtp_dyn_payload_t *rtp_dyn_payload)
+{
+ srtp_add_address(pinfo, ptype, addr, port, other_port, setup_method, setup_frame_number, media_types, rtp_dyn_payload, NULL, NULL);
+}
+
+static gboolean
+dissect_rtp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
+{
+ guint8 octet1, octet2;
+ unsigned int version, payload_type;
+ unsigned int offset = 0;
+ gint padding_count;
+
+ if (tvb_captured_length_remaining(tvb, offset) < 2) {
+ return FALSE;
+ }
+
+ /* Get the fields in the first octet */
+ octet1 = tvb_get_guint8( tvb, offset );
+ version = RTP_VERSION( octet1 );
+
+ /* XXX: Why are we calling these dissectors from the *heuristic*
+ * RTP dissector? These almost all have their own heuristic dissector,
+ * enabled by default (unlike RTP, which has a much less accurate
+ * heuristic.) We should just reject and let the protocols' own heuristic
+ * dissectors handle this.
+ */
+ if (version == 0) {
+ if (!(tvb_memeql(tvb, 4, (const guint8*)"ZRTP", 4)))
+ {
+ call_dissector_only(zrtp_handle, tvb, pinfo, tree, NULL);
+ return TRUE;
+ } else {
+ switch (global_rtp_version0_type) {
+ case RTP0_STUN:
+ return call_dissector_only(stun_heur_handle, tvb, pinfo, tree, NULL);
+ case RTP0_CLASSICSTUN:
+ return call_dissector_only(classicstun_heur_handle, tvb, pinfo, tree, NULL);
+
+ case RTP0_T38:
+ /* XXX: Should really be calling a heuristic dissector for T38 ??? */
+ call_dissector_only(t38_handle, tvb, pinfo, tree, NULL);
+ return TRUE;
+
+ case RTP0_SPRT:
+ call_dissector_only(sprt_handle, tvb, pinfo, tree, NULL);
+ return TRUE;
+
+ case RTP0_INVALID:
+ case RTP0_RFC7983:
+ default:
+ return FALSE; /* Unknown or unsupported version */
+ }
+ }
+ } else if (version != 2) {
+ /* Unknown or unsupported version */
+ return FALSE;
+ }
+
+ octet2 = tvb_get_guint8( tvb, offset + 1 );
+ payload_type = RTP_PAYLOAD_TYPE( octet2 );
+
+ if (payload_type >= 72 && payload_type <= 76) {
+ /* XXX: This range is definitely excluded by RFCs 3550, 3551.
+ * There's an argument, per RFC 5761, for expanding the
+ * excluded range to [FIRST_RTCP_CONFLICT_PAYLOAD_TYPE,
+ * LAST_RTCP_CONFLICT_PAYLOAD_TYPE] in the heuristic dissector,
+ * leaving those values only when specificed by other means
+ * (SDP, Decode As, etc.)
+ */
+ return FALSE;
+ }
+
+ /* Skip fixed header */
+ offset += 12;
+
+ offset += 4 * RTP_CSRC_COUNT( octet1 );
+ if (RTP_EXTENSION( octet1 )) {
+ if (tvb_captured_length_remaining(tvb, offset) < 4) {
+ return FALSE;
+ }
+ offset += 4 + 4*tvb_get_guint16(tvb, offset+2, ENC_BIG_ENDIAN);
+ }
+ if (tvb_reported_length(tvb) < offset) {
+ return FALSE;
+ }
+ if (RTP_PADDING( octet1 )) {
+ if (tvb_captured_length(tvb) == tvb_reported_length(tvb)) {
+ /* We can test the padding if the last octet is present. */
+ padding_count = tvb_get_guint8(tvb, tvb_reported_length(tvb) - 1);
+ if (tvb_reported_length_remaining(tvb, offset) < padding_count ||
+ padding_count == 0) {
+ return FALSE;
+ }
+ }
+ }
+
+ /* Create a conversation in case none exists so as to allow reassembly code to work */
+ if (!find_conversation(pinfo->num, &pinfo->net_dst, &pinfo->net_src, conversation_pt_to_conversation_type(pinfo->ptype),
+ pinfo->destport, pinfo->srcport, NO_ADDR_B)) {
+ conversation_t *p_conv;
+ struct _rtp_conversation_info *p_conv_data;
+ p_conv = conversation_new(pinfo->num, &pinfo->net_dst, &pinfo->net_src, conversation_pt_to_conversation_type(pinfo->ptype),
+ pinfo->destport, pinfo->srcport, NO_ADDR2);
+ p_conv_data = (struct _rtp_conversation_info *)conversation_get_proto_data(p_conv, proto_rtp);
+ if (! p_conv_data) {
+ /* Create conversation data */
+ p_conv_data = wmem_new0(wmem_file_scope(), struct _rtp_conversation_info);
+ p_conv_data->ssrc_number_space = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
+ p_conv_data->rtp_conv_info = wmem_new(wmem_file_scope(), rtp_private_conv_info);
+ p_conv_data->rtp_conv_info->multisegment_pdus = wmem_tree_new(wmem_file_scope());
+ conversation_add_proto_data(p_conv, proto_rtp, p_conv_data);
+ }
+ (void) g_strlcpy(p_conv_data->method, "HEUR RTP", MAX_RTP_SETUP_METHOD_SIZE+1);
+ p_conv_data->frame_number = pinfo->num;
+ p_conv_data->media_types = 0;
+ p_conv_data->srtp_info = NULL;
+ p_conv_data->bta2dp_info = NULL;
+ p_conv_data->btvdp_info = NULL;
+ }
+ dissect_rtp( tvb, pinfo, tree, data );
+ return TRUE;
+}
+
+/*
+ * Process the payload of the RTP packet, hand it to the subdissector
+ */
+static void
+process_rtp_payload(tvbuff_t *newtvb, packet_info *pinfo, proto_tree *tree,
+ proto_tree *rtp_tree, unsigned int payload_type,
+ struct _rtp_info *rtp_info)
+{
+ struct _rtp_packet_info *p_packet_data;
+ int payload_len;
+ struct srtp_info *srtp_info;
+ int offset = 0;
+ proto_item *rtp_data;
+
+ payload_len = tvb_captured_length_remaining(newtvb, offset);
+
+ /* first check if this is added as an SRTP stream - if so, don't try to dissector the payload data for now */
+ p_packet_data = (struct _rtp_packet_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_rtp, RTP_CONVERSATION_PROTO_DATA);
+ if (p_packet_data && p_packet_data->srtp_info) {
+ srtp_info = p_packet_data->srtp_info;
+ payload_len -= srtp_info->mki_len + srtp_info->auth_tag_len;
+#if 0
+#error Currently the srtp_info structure contains no cipher data, see packet-sdp.c adding dummy_srtp_info structure
+ if (p_conv_data->srtp_info->encryption_algorithm == SRTP_ENC_ALG_NULL) {
+ if (rtp_tree)
+ proto_tree_add_item(rtp_tree, hf_srtp_null_encrypted_payload, newtvb, offset, payload_len, ENC_NA);
+ }
+ else
+#endif
+ {
+ if (rtp_tree)
+ proto_tree_add_item(rtp_tree, hf_srtp_encrypted_payload, newtvb, offset, payload_len, ENC_NA);
+ }
+ offset += payload_len;
+
+ if (srtp_info->mki_len) {
+ proto_tree_add_item(rtp_tree, hf_srtp_mki, newtvb, offset, srtp_info->mki_len, ENC_NA);
+ offset += srtp_info->mki_len;
+ }
+
+ if (srtp_info->auth_tag_len) {
+ proto_tree_add_item(rtp_tree, hf_srtp_auth_tag, newtvb, offset, srtp_info->auth_tag_len, ENC_NA);
+ /*offset += srtp_info->auth_tag_len;*/
+ }
+ return;
+
+ } if (p_packet_data && p_packet_data->bta2dp_info) {
+ tvbuff_t *nexttvb;
+ gint suboffset = 0;
+
+ if (p_packet_data->bta2dp_info->content_protection_type == BTAVDTP_CONTENT_PROTECTION_TYPE_SCMS_T) {
+ nexttvb = tvb_new_subset_length(newtvb, 0, 1);
+ call_dissector(bta2dp_content_protection_header_scms_t, nexttvb, pinfo, tree);
+ suboffset = 1;
+ }
+
+ nexttvb = tvb_new_subset_remaining(newtvb, suboffset);
+ if (p_packet_data->bta2dp_info->codec_dissector)
+ call_dissector_with_data(p_packet_data->bta2dp_info->codec_dissector, nexttvb, pinfo, tree, p_packet_data->bta2dp_info);
+ else
+ call_data_dissector(nexttvb, pinfo, tree);
+
+ return;
+
+ } if (p_packet_data && p_packet_data->btvdp_info) {
+ tvbuff_t *nexttvb;
+ gint suboffset = 0;
+
+ if (p_packet_data->btvdp_info->content_protection_type == BTAVDTP_CONTENT_PROTECTION_TYPE_SCMS_T) {
+ nexttvb = tvb_new_subset_length(newtvb, 0, 1);
+ call_dissector(btvdp_content_protection_header_scms_t, nexttvb, pinfo, tree);
+ suboffset = 1;
+ }
+
+ nexttvb = tvb_new_subset_remaining(newtvb, suboffset);
+ if (p_packet_data->btvdp_info->codec_dissector)
+ call_dissector_with_data(p_packet_data->btvdp_info->codec_dissector, nexttvb, pinfo, tree, p_packet_data->btvdp_info);
+ else
+ call_data_dissector(nexttvb, pinfo, tree);
+
+ return;
+ }
+
+ rtp_data = proto_tree_add_item(rtp_tree, hf_rtp_data, newtvb, 0, -1, ENC_NA);
+
+ /* We have checked for !p_conv_data->bta2dp_info && !p_conv_data->btvdp_info above*/
+ if (p_packet_data && payload_type >= PT_UNDF_96 && payload_type <= PT_UNDF_127) {
+ /* if the payload type is dynamic, we check if the conv is set and we look for the pt definition */
+ if (p_packet_data->rtp_dyn_payload) {
+ const gchar *payload_type_str = rtp_dyn_payload_get_name(p_packet_data->rtp_dyn_payload, payload_type);
+ if (payload_type_str) {
+ int len;
+ len = dissector_try_string(rtp_dyn_pt_dissector_table,
+ payload_type_str, newtvb, pinfo, tree, rtp_info);
+ /* If payload type string set from conversation and
+ * no matching dissector found it's probably because no subdissector
+ * exists. Don't call the dissectors based on payload number
+ * as that'd probably be the wrong dissector in this case.
+ * Just add it as data.
+ */
+ if (len > 0)
+ proto_item_set_hidden(rtp_data);
+ return;
+ }
+ }
+ }
+
+ /* if we don't found, it is static OR could be set static from the preferences */
+ if (dissector_try_uint_new(rtp_pt_dissector_table, payload_type, newtvb, pinfo, tree, TRUE, rtp_info))
+ proto_item_set_hidden(rtp_data);
+}
+
+/* Rtp payload reassembly
+ *
+ * This handles the reassembly of PDUs for higher-level protocols.
+ *
+ * We're a bit limited on how we can cope with out-of-order packets, because
+ * we don't have any idea of where the datagram boundaries are. So if we see
+ * packets A, C, B (all of which comprise a single datagram), we cannot know
+ * that C should be added to the same datagram as A, until we come to B (which
+ * may or may not actually be present...).
+ *
+ * What we end up doing in this case is passing A+B to the subdissector as one
+ * datagram, and make out that a new one starts on C.
+ */
+static void
+dissect_rtp_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ proto_tree *rtp_tree, int offset, unsigned int data_len,
+ unsigned int data_reported_len, unsigned int payload_type,
+ struct _rtp_info *rtp_info)
+{
+ tvbuff_t *newtvb;
+ struct _rtp_packet_info *p_packet_data;
+ gboolean must_desegment = FALSE;
+ rtp_private_conv_info *finfo = NULL;
+ rtp_multisegment_pdu *msp;
+ guint32 seqno;
+ guint16 save_can_desegment;
+
+ /* Retrieve RTPs idea of a conversation */
+ p_packet_data = (struct _rtp_packet_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_rtp, RTP_CONVERSATION_PROTO_DATA);
+
+ if(p_packet_data != NULL)
+ finfo = p_packet_data->rtp_conv_info;
+
+ if(finfo == NULL || !desegment_rtp) {
+ /* Hand the whole lot off to the subdissector */
+ newtvb = tvb_new_subset_length_caplen(tvb, offset, data_len, data_reported_len);
+ process_rtp_payload(newtvb, pinfo, tree, rtp_tree, payload_type, rtp_info);
+ return;
+ }
+
+ seqno = p_packet_data->extended_seqno;
+
+ /* Preserve the current desegmentation ability in case this is
+ * RTP encapsulated in TCP (RFC 4571).
+ */
+ save_can_desegment = pinfo->can_desegment;
+ pinfo->can_desegment = 2;
+ pinfo->desegment_offset = 0;
+ pinfo->desegment_len = 0;
+
+#ifdef DEBUG_FRAGMENTS
+ ws_debug("%d: RTP Part of convo %d(%p); seqno %d",
+ pinfo->num,
+ p_packet_data->frame_number, p_packet_data,
+ seqno
+ );
+#endif
+
+ /* look for a pdu which we might be extending */
+ msp = (rtp_multisegment_pdu *)wmem_tree_lookup32_le(finfo->multisegment_pdus, seqno-1);
+
+ if(msp && msp->startseq < seqno && msp->endseq >= seqno) {
+ guint32 fid = msp->startseq;
+ fragment_head *fd_head;
+
+#ifdef DEBUG_FRAGMENTS
+ ws_debug("\tContinues fragment %d", fid);
+#endif
+
+ /* we always assume the datagram is complete; if this is the
+ * first pass, that's our best guess, and if it's not, what we
+ * say gets ignored anyway.
+ */
+ fd_head = fragment_add_seq(&rtp_reassembly_table,
+ tvb, offset, pinfo, fid, NULL,
+ seqno-msp->startseq, data_len,
+ FALSE, 0);
+
+ newtvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled RTP", fd_head,
+ &rtp_fragment_items, NULL, tree);
+
+#ifdef DEBUG_FRAGMENTS
+ ws_debug("\tFragment Coalesced; fd_head=%p, newtvb=%p (len %d)", fd_head, newtvb,
+ newtvb?tvb_reported_length(newtvb):0);
+#endif
+
+ if(newtvb != NULL) {
+ /* Hand off to the subdissector */
+ process_rtp_payload(newtvb, pinfo, tree, rtp_tree, payload_type, rtp_info);
+
+ /*
+ * Check to see if there were any complete fragments within the chunk
+ */
+ if( pinfo->desegment_len )
+ {
+ if (pinfo->desegment_offset == 0) {
+#ifdef DEBUG_FRAGMENTS
+ ws_debug("\tNo complete pdus in payload" );
+#endif
+ /* Mark the fragments as not complete yet */
+ fragment_set_partial_reassembly(&rtp_reassembly_table,
+ pinfo, fid, NULL);
+
+ /* we must need another segment */
+ msp->endseq = MIN(msp->endseq, seqno) + 1;
+
+ }
+
+ /* the higher-level dissector has asked for some more data - ie,
+ the end of this segment does not coincide with the end of a
+ higher-level PDU. */
+ must_desegment = TRUE;
+ }
+
+ }
+
+ }
+ else
+ {
+ /*
+ * The segment is not the continuation of a fragmented segment
+ * so process it as normal
+ */
+#ifdef DEBUG_FRAGMENTS
+ ws_debug("\tRTP non-fragment payload");
+#endif
+ newtvb = tvb_new_subset_length_caplen( tvb, offset, data_len, data_reported_len );
+
+ /* Hand off to the subdissector */
+ process_rtp_payload(newtvb, pinfo, tree, rtp_tree, payload_type, rtp_info);
+
+ if(pinfo->desegment_len) {
+ /* the higher-level dissector has asked for some more data - ie,
+ the end of this segment does not coincide with the end of a
+ higher-level PDU. */
+ must_desegment = TRUE;
+ }
+ }
+
+ /*
+ * There were bytes left over that the higher protocol couldn't dissect so save them
+ */
+ if(must_desegment)
+ {
+ guint32 deseg_offset = pinfo->desegment_offset;
+ guint32 frag_len = tvb_reported_length_remaining(newtvb, deseg_offset);
+ fragment_head *fd_head;
+
+#ifdef DEBUG_FRAGMENTS
+ ws_debug("\tRTP Must Desegment: tvb_len=%d ds_len=%d %d frag_len=%d ds_off=%d",
+ tvb_reported_length(newtvb),
+ pinfo->desegment_len,
+ pinfo->fd->visited,
+ frag_len,
+ deseg_offset);
+#endif
+ /* allocate a new msp for this pdu */
+ if (!PINFO_FD_VISITED(pinfo)) {
+ msp = wmem_new(wmem_file_scope(), rtp_multisegment_pdu);
+ msp->startseq = seqno;
+ msp->endseq = seqno+1;
+ wmem_tree_insert32(finfo->multisegment_pdus, seqno, msp);
+ }
+
+ /*
+ * Add the fragment to the fragment table
+ */
+ fd_head = fragment_add_seq(&rtp_reassembly_table,
+ newtvb, deseg_offset, pinfo, seqno, NULL, 0, frag_len,
+ TRUE, 0);
+
+ if(fd_head != NULL)
+ {
+ if( fd_head->reassembled_in != 0 && !(fd_head->flags & FD_PARTIAL_REASSEMBLY) )
+ {
+ proto_item *rtp_tree_item;
+ rtp_tree_item = proto_tree_add_uint( tree, hf_rtp_reassembled_in,
+ newtvb, deseg_offset, tvb_reported_length_remaining(newtvb, deseg_offset),
+ fd_head->reassembled_in);
+ proto_item_set_generated(rtp_tree_item);
+#ifdef DEBUG_FRAGMENTS
+ ws_debug("\tReassembled in %d", fd_head->reassembled_in);
+#endif
+ }
+ else if (fd_head->reassembled_in == 0)
+ {
+#ifdef DEBUG_FRAGMENTS
+ ws_debug("\tUnfinished fragment");
+#endif
+ /* this fragment is never reassembled */
+ proto_tree_add_expert(tree, pinfo, &ei_rtp_fragment_unfinished, tvb, deseg_offset, -1);
+ }
+ }
+ else
+ {
+ /*
+ * This fragment was the first fragment in a new entry in the
+ * frag_table; we don't yet know where it is reassembled
+ */
+#ifdef DEBUG_FRAGMENTS
+ ws_debug("\tnew pdu");
+#endif
+ }
+
+ if( pinfo->desegment_offset == 0 )
+ {
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTP");
+ col_set_str(pinfo->cinfo, COL_INFO, "[RTP segment of a reassembled PDU]");
+ }
+ }
+
+ /* Restore desegmentation ability */
+ pinfo->can_desegment = save_can_desegment;
+ pinfo->desegment_offset = 0;
+ pinfo->desegment_len = 0;
+}
+
+static int
+dissect_rtp_rfc2198(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
+{
+ volatile gint offset = 0;
+ int cnt;
+ gboolean hdr_follow = TRUE;
+ proto_tree *rfc2198_tree;
+ rfc2198_hdr *hdr_last;
+ rfc2198_hdr *hdr_chain = NULL;
+ struct _rtp_packet_info *p_packet_data;
+ struct _rtp_info* rtp_info = NULL;
+ struct _rtp_info rfc2198_rtp_info;
+ volatile unsigned rtp_info_offset = 0;
+
+ if (data) {
+ rtp_info = (struct _rtp_info*)data;
+ rfc2198_rtp_info = *rtp_info;
+ rtp_info_offset = rtp_info->info_payload_offset;
+ }
+
+ /* Retrieve RTPs idea of a conversation */
+ p_packet_data = (struct _rtp_packet_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_rtp, RTP_CONVERSATION_PROTO_DATA);
+
+ /* Add try to RFC 2198 data */
+ rfc2198_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_rtp_rfc2198, NULL, "RFC 2198: Redundant Audio Data");
+
+ hdr_last = NULL;
+ cnt = 0;
+ while (hdr_follow) {
+ proto_item *ti;
+ proto_tree *rfc2198_hdr_tree;
+ const gchar *payload_type_str;
+ rfc2198_hdr *hdr_new;
+ guint8 octet1;
+
+ cnt++;
+ payload_type_str = NULL;
+
+ /* Allocate and fill in header */
+ hdr_new = wmem_new0(pinfo->pool, rfc2198_hdr);
+ hdr_new->next = NULL;
+ octet1 = tvb_get_guint8(tvb, offset);
+ hdr_new->pt = RTP_PAYLOAD_TYPE(octet1);
+ hdr_follow = (octet1 & 0x80);
+
+ /* Save the payload type for Decode As */
+ p_add_proto_data(pinfo->pool, pinfo, proto_rtp, RTP_DECODE_AS_PROTO_DATA, GUINT_TO_POINTER(hdr_new->pt));
+
+ /* if it is dynamic payload, let use the conv data to see if it is defined */
+ if ((hdr_new->pt > 95) && (hdr_new->pt < 128)) {
+ if (p_packet_data && p_packet_data->rtp_dyn_payload){
+ rtp_dyn_payload_get_full(p_packet_data->rtp_dyn_payload, hdr_new->pt, &payload_type_str, &hdr_new->payload_rate, &hdr_new->payload_channels, &hdr_new->payload_fmtp_map);
+ hdr_new->payload_type_str = payload_type_str;
+ } else {
+ /* See if we have a dissector tied to the dynamic payload
+ * through preferences / Decode As */
+ dissector_handle_t pt_dissector_handle;
+
+ pt_dissector_handle = dissector_get_uint_handle(rtp_pt_dissector_table, hdr_new->pt);
+ if (pt_dissector_handle) {
+ hdr_new->payload_type_str = dissector_handle_get_dissector_name(pt_dissector_handle);
+ }
+ }
+ }
+ /* Add a subtree for this header and add items */
+ rfc2198_hdr_tree = proto_tree_add_subtree_format(rfc2198_tree, tvb, offset, (hdr_follow)?4:1,
+ ett_rtp_rfc2198_hdr, &ti, "Header %u", cnt);
+ proto_tree_add_item(rfc2198_hdr_tree, hf_rtp_rfc2198_follow, tvb, offset, 1, ENC_BIG_ENDIAN );
+ proto_tree_add_uint_format_value(rfc2198_hdr_tree, hf_rtp_payload_type, tvb,
+ offset, 1, octet1, "%s (%u)",
+ payload_type_str ? payload_type_str : val_to_str_ext_const(hdr_new->pt, &rtp_payload_type_vals_ext, "Unknown"),
+ hdr_new->pt);
+ proto_item_append_text(ti, ": PT=%s",
+ payload_type_str ? payload_type_str :
+ val_to_str_ext(hdr_new->pt, &rtp_payload_type_vals_ext, "Unknown (%u)"));
+ offset += 1;
+
+ /* Timestamp offset and block length don't apply to last header */
+ if (hdr_follow) {
+ proto_tree_add_item(rfc2198_hdr_tree, hf_rtp_rfc2198_tm_off, tvb, offset, 2, ENC_BIG_ENDIAN );
+ proto_tree_add_item(rfc2198_hdr_tree, hf_rtp_rfc2198_bl_len, tvb, offset + 1, 2, ENC_BIG_ENDIAN );
+ hdr_new->len = tvb_get_ntohs(tvb, offset + 1) & 0x03FF;
+ proto_item_append_text(ti, ", len=%u", hdr_new->len);
+ offset += 3;
+ } else {
+ hdr_new->len = -1;
+ hdr_follow = FALSE;
+ }
+
+ if (hdr_last) {
+ hdr_last->next = hdr_new;
+ } else {
+ hdr_chain = hdr_new;
+ }
+ hdr_last = hdr_new;
+ }
+
+ /* Dissect each data block according to the header info */
+ hdr_last = hdr_chain;
+ while (hdr_last) {
+ hdr_last->offset = offset;
+ if (!hdr_last->next) {
+ hdr_last->len = tvb_reported_length_remaining(tvb, offset);
+ }
+ if (rtp_info) {
+ rfc2198_rtp_info.info_payload_offset = rtp_info_offset + hdr_last->offset;
+ rfc2198_rtp_info.info_payload_len = hdr_last->len;
+ rfc2198_rtp_info.info_payload_type = hdr_last->pt;
+ rfc2198_rtp_info.info_payload_type_str = hdr_last->payload_type_str;
+ rfc2198_rtp_info.info_payload_rate = hdr_last->payload_rate;
+ rfc2198_rtp_info.info_payload_channels = hdr_last->payload_channels;
+ rfc2198_rtp_info.info_payload_fmtp_map = hdr_last->payload_fmtp_map;
+ }
+ const char *saved_proto = pinfo->current_proto;
+ TRY {
+ dissect_rtp_data(tvb, pinfo, tree, rfc2198_tree, hdr_last->offset, hdr_last->len, hdr_last->len, hdr_last->pt, &rfc2198_rtp_info);
+ }
+ CATCH_NONFATAL_ERRORS {
+ show_exception(tvb, pinfo, rfc2198_tree, EXCEPT_CODE, GET_MESSAGE);
+ pinfo->current_proto = saved_proto;
+ }
+ ENDTRY;
+ if (rtp_info && rfc2198_deencapsulate && !hdr_last->next) {
+ /* Set the payload for the tap to that of the primary encoding
+ * to remove the RFC 2198 encapsulation. (Since this is the
+ * last encoding in the packet, the calculated length includes
+ * the padding and padding stays the same.)
+ * Ideally we should process the redundant encoding or FEC,
+ * but just treating the primary encoding as the only payload
+ * for the tap is closer than doing nothing, and at least has
+ * some chance of playing or saving the primary media payload.
+ *
+ * XXX: WebRTC/Chromium, when using RED with ULPFEC (RFC 5109),
+ * violates the RFCs by having the FEC set in separate packets
+ * as a different primary encoding (using duplicate sequence
+ * numbers already used by the video.) This is done because of
+ * a concern that the combined payload size of FEC plus video
+ * encodings like VP8 could push a packet over the MTU size,
+ * also a problem.
+ * See RFC 8872 3.2.4 "RTP Payload Type" and Appendix A
+ * "Dismissing Payload Type Multiplexing," also
+ * https://bugs.chromium.org/p/webrtc/issues/detail?id=9188
+ * https://bugs.chromium.org/p/webrtc/issues/detail?id=12530
+ * https://bugs.chromium.org/p/webrtc/issues/detail?id=1467
+ * However, since duplicate sequence numbers as used, a user
+ * Ignoring all the FEC packets could be a workaround.
+ * RFC 2198 in WebRTC/Chromium with actual redundant audio is
+ * RFC-compliant, though:
+ * https://bugs.chromium.org/p/webrtc/issues/detail?id=11640
+ */
+ *rtp_info = rfc2198_rtp_info;
+ }
+ offset += hdr_last->len;
+ hdr_last = hdr_last->next;
+ }
+ return tvb_captured_length(tvb);
+}
+
+static int
+dissect_full_rfc4571(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
+{
+ /* rfc4571 packet frame
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ ---------------------------------------------------------------
+ | LENGTH | RTP or RTCP packet ... |
+ ---------------------------------------------------------------
+ */
+ gint offset = 0;
+ guint32 length = 0;
+ proto_tree_add_item_ret_uint(tree, hf_rfc4571_header_len, tvb, offset, 2, ENC_NA, &length);
+ if (length == 0) {
+ return 2;
+ }
+
+ offset += 2;
+ tvbuff_t *tvb_sub;
+ tvb_sub = tvb_new_subset_remaining(tvb, offset);
+
+ dissect_rtp(tvb_sub, pinfo, tree, data);
+ return tvb_reported_length(tvb);
+}
+
+static guint
+get_rtp_rfc4571_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
+{
+ guint16 rtp_length = tvb_get_ntohs(tvb, offset); /* length field is at the beginning, 2 bytes */
+ return (guint)rtp_length + 2; /* plus the length field */
+}
+
+#define RTP_RFC4571_HEADER_LEN 2
+
+static int
+dissect_rtp_rfc4571(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
+{
+ tcp_dissect_pdus(tvb, pinfo, tree, TRUE, RTP_RFC4571_HEADER_LEN,
+ get_rtp_rfc4571_len, dissect_full_rfc4571, data);
+ return tvb_captured_length(tvb);
+}
+
+static void
+dissect_rtp_hext_rfc5285_onebyte( tvbuff_t *tvb, packet_info *pinfo,
+ proto_tree *rtp_hext_tree )
+{
+ proto_tree *rtp_hext_rfc5285_tree = NULL;
+ guint ext_offset = 0;
+
+ while (ext_offset < tvb_captured_length (tvb)) {
+ guint8 ext_hdr_hdr;
+ guint8 ext_id;
+ guint8 ext_length;
+ guint start_ext_offset;
+ tvbuff_t *subtvb;
+
+ /* Skip bytes with the value 0, they are padding */
+ start_ext_offset = ext_offset;
+ while (tvb_get_guint8 (tvb, ext_offset) == 0) {
+ ext_offset ++;
+ if (ext_offset >= tvb_captured_length (tvb))
+ return;
+ }
+
+ /* Add padding */
+ if (ext_offset > start_ext_offset)
+ proto_tree_add_item(rtp_hext_tree, hf_rtp_padding_data, tvb, start_ext_offset, ext_offset-start_ext_offset, ENC_NA );
+
+ ext_hdr_hdr = tvb_get_guint8 (tvb, ext_offset);
+ ext_id = ext_hdr_hdr >> 4;
+
+ /* 15 is for future extensibility, ignore length, etc and stop processing packet if it shows up */
+ if (ext_id == 15)
+ return;
+
+ ext_length = (ext_hdr_hdr & 0x0F) + 1;
+
+ /* Exit on malformed extension headers */
+ if (ext_offset + ext_length + 1 > tvb_captured_length (tvb)) {
+ return;
+ }
+
+ if (rtp_hext_tree) {
+ rtp_hext_rfc5285_tree = proto_tree_add_subtree(rtp_hext_tree, tvb, ext_offset, ext_length + 1,
+ ett_hdr_ext_rfc5285, NULL, "RFC 5285 Header Extension (One-Byte Header)");
+
+ proto_tree_add_uint( rtp_hext_rfc5285_tree, hf_rtp_ext_rfc5285_id, tvb, ext_offset, 1, ext_id);
+ proto_tree_add_uint( rtp_hext_rfc5285_tree, hf_rtp_ext_rfc5285_length, tvb, ext_offset, 1, ext_length);
+ }
+ ext_offset ++;
+
+ subtvb = tvb_new_subset_length(tvb, ext_offset, ext_length);
+ if (!dissector_try_uint (rtp_hdr_ext_rfc5285_dissector_table, ext_id, subtvb, pinfo, rtp_hext_rfc5285_tree)) {
+ if (rtp_hext_tree)
+ proto_tree_add_item(rtp_hext_rfc5285_tree, hf_rtp_ext_rfc5285_data, subtvb, 0, ext_length, ENC_NA );
+ }
+
+ ext_offset += ext_length;
+ }
+}
+
+
+static void
+dissect_rtp_hext_rfc5285_twobytes(tvbuff_t *parent_tvb, guint id_offset,
+ guint8 id, tvbuff_t *tvb, packet_info *pinfo, proto_tree *rtp_hext_tree)
+{
+ proto_tree *rtp_hext_rfc5285_tree = NULL;
+ guint ext_offset = 0, start_ext_offset;
+
+ while (ext_offset + 2 < tvb_captured_length (tvb)) {
+ guint8 ext_id;
+ guint8 ext_length;
+ tvbuff_t *subtvb;
+
+ /* Skip bytes with the value 0, they are padding */
+ start_ext_offset = ext_offset;
+ while (tvb_get_guint8 (tvb, ext_offset) == 0) {
+ if (ext_offset + 2 >= tvb_captured_length (tvb))
+ return;
+ ext_offset ++;
+ }
+ /* Add padding */
+ if (ext_offset > start_ext_offset)
+ proto_tree_add_item(rtp_hext_tree, hf_rtp_padding_data, tvb, start_ext_offset, ext_offset-start_ext_offset, ENC_NA );
+
+ ext_id = tvb_get_guint8 (tvb, ext_offset);
+ ext_length = tvb_get_guint8 (tvb, ext_offset + 1);
+
+ if (rtp_hext_tree) {
+ rtp_hext_rfc5285_tree = proto_tree_add_subtree(rtp_hext_tree, tvb, ext_offset, ext_length + 2,
+ ett_hdr_ext_rfc5285, NULL, "RFC 5285 Header Extension (Two-Byte Header)");
+
+ proto_tree_add_uint( rtp_hext_rfc5285_tree, hf_rtp_ext_rfc5285_appbits, parent_tvb, id_offset + 1, 1, id & 0x000F);
+ proto_tree_add_uint( rtp_hext_rfc5285_tree, hf_rtp_ext_rfc5285_id, tvb, ext_offset, 1, ext_id);
+ proto_tree_add_uint( rtp_hext_rfc5285_tree, hf_rtp_ext_rfc5285_length, tvb, ext_offset + 1, 1, ext_length);
+ }
+
+ ext_offset += 2;
+
+ subtvb = tvb_new_subset_length(tvb, ext_offset, ext_length);
+ if (ext_length && !dissector_try_uint (rtp_hdr_ext_rfc5285_dissector_table, ext_id, subtvb, pinfo, rtp_hext_rfc5285_tree)) {
+ proto_tree_add_item(rtp_hext_rfc5285_tree, hf_rtp_ext_rfc5285_data, subtvb, 0, ext_length, ENC_NA );
+ }
+
+ ext_offset += ext_length;
+ }
+}
+
+static gint
+dissect_rtp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
+{
+ proto_item *ti = NULL;
+ proto_tree *volatile rtp_tree = NULL;
+ guint8 octet1, octet2;
+ unsigned int version;
+ gboolean padding_set;
+ gboolean extension_set;
+ unsigned int csrc_count;
+ gboolean marker_set;
+ unsigned int payload_type;
+ const gchar *payload_type_str = NULL;
+ gboolean is_srtp = FALSE;
+ unsigned int i;
+ gint length, reported_length;
+ int data_len;
+ volatile unsigned int offset = 0;
+ guint16 seq_num;
+ guint32 timestamp;
+ guint32 sync_src;
+ struct _rtp_packet_info *p_packet_data;
+ /*struct srtp_info *srtp_info = NULL;*/
+ /*unsigned int srtp_offset;*/
+ const char *pt = NULL;
+ struct _rtp_info *rtp_info;
+ static int * const octet1_fields[] = {
+ &hf_rtp_version,
+ &hf_rtp_padding,
+ &hf_rtp_extension,
+ &hf_rtp_csrc_count,
+ NULL
+ };
+
+ /* Get the fields in the first octet */
+ octet1 = tvb_get_guint8( tvb, offset );
+ version = RTP_VERSION( octet1 );
+
+ /* RFC 7983 gives current best practice in demultiplexing RTP packets:
+ * Examine the first byte of the packet:
+ * +----------------+
+ * | [0..3] -+--> forward to STUN
+ * | |
+ * | [16..19] -+--> forward to ZRTP
+ * | |
+ * packet --> | [20..63] -+--> forward to DTLS
+ * | |
+ * | [64..79] -+--> forward to TURN Channel
+ * | |
+ * | [128..191] -+--> forward to RTP/RTCP
+ * +----------------+
+ *
+ * DTLS-SRTP MUST support multiplexing of DTLS and RTP over the same
+ * port pair (RFCs 5764, 8835), and this frequently occurs after SDP
+ * has been used to set up a RTP conversation and set the conversation
+ * dissector RTP. In addition, STUN packets sharing one port are common
+ * as well.
+ *
+ * In practice, RTP0_INVALID rejects packets and lets heuristic dissectors
+ * take a look. The STUN, ZRTP, and DTLS heuristic dissectors are all
+ * enabled by default so out of the box it more or less looks correct - at
+ * least on the second pass, on tshark there's incorrect RTP information in
+ * the tree. However, the STUN heuristic dissector can change the
+ * dissector for the conversation to itself (the non-heuristic dissector
+ * does not), see #18832, and TURN ChannelData messages are impossible to
+ * heuristically detect.
+ */
+ if (global_rtp_version0_type == RTP0_RFC7983) {
+ switch (version) {
+ case 0:
+ if (octet1 < 4) {
+ call_dissector(stun_handle, tvb, pinfo, tree);
+ return tvb_captured_length(tvb);
+ } else if ((octet1 & 0xfc) == 0x10) {
+ call_dissector(zrtp_handle, tvb,pinfo, tree);
+ return tvb_captured_length(tvb);
+ } else if (octet1 > 19) {
+ call_dissector(dtls_handle, tvb,pinfo, tree);
+ return tvb_captured_length(tvb);
+ }
+ break;
+ case 1:
+ if (octet1 < 80) {
+ /* The STUN dissector will dissect TURN ChannelData
+ * XXX: Maybe we should call the turnchannel dissector?
+ *
+ * Should we be assuming we have TURN ChannelData for
+ * the RTP0_STUN and option too?
+ */
+ call_dissector(stun_handle, tvb, pinfo, tree);
+ return tvb_captured_length(tvb);
+ }
+ break;
+ case 3:
+ if (octet1 == 0xFF) {
+ if (tvb_get_guint8( tvb, offset + 1 ) == 0x10) {
+ /* Special MS-TURN Multiplexed TURN Channel */
+ call_dissector(stun_handle, tvb, pinfo, tree);
+ return tvb_captured_length(tvb);
+ }
+ }
+ /* FALLTHROUGH */
+ case 2:
+ default:
+ break;
+ }
+ } else if (version == 0) {
+ switch (global_rtp_version0_type) {
+ case RTP0_STUN:
+ call_dissector(stun_handle, tvb, pinfo, tree);
+ return tvb_captured_length(tvb);
+ case RTP0_CLASSICSTUN:
+ call_dissector(classicstun_handle, tvb, pinfo, tree);
+ return tvb_captured_length(tvb);
+
+ case RTP0_T38:
+ call_dissector(t38_handle, tvb, pinfo, tree);
+ return tvb_captured_length(tvb);
+
+ case RTP0_SPRT:
+ call_dissector(sprt_handle, tvb, pinfo, tree);
+ return tvb_captured_length(tvb);
+
+ case RTP0_INVALID:
+ if (!(tvb_memeql(tvb, 4, (const guint8*)"ZRTP", 4)))
+ {
+ call_dissector(zrtp_handle, tvb,pinfo, tree);
+ return tvb_captured_length(tvb);
+ }
+ default:
+ ; /* Unknown or unsupported version (let it fall through) */
+ }
+ }
+
+ /* fill in the rtp_info structure */
+ rtp_info = wmem_new0(pinfo->pool, struct _rtp_info);
+ rtp_info->info_version = version;
+ if (version != 2) {
+ /*
+ * Unknown or unsupported version.
+ */
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTP");
+
+ col_add_fstr( pinfo->cinfo, COL_INFO,
+ "Unknown RTP version %u", version);
+
+ if ( tree ) {
+ ti = proto_tree_add_item( tree, proto_rtp, tvb, offset, -1, ENC_NA );
+ rtp_tree = proto_item_add_subtree( ti, ett_rtp );
+
+ proto_tree_add_uint( rtp_tree, hf_rtp_version, tvb,
+ offset, 1, octet1);
+ }
+ /* XXX: Offset is zero here, so in practice this rejects the packet
+ * and lets heuristic dissectors make an attempt, though after
+ * adding entries to the tree (at least on a first pass in tshark.)
+ */
+ return offset;
+ }
+
+ padding_set = RTP_PADDING( octet1 );
+ extension_set = RTP_EXTENSION( octet1 );
+ csrc_count = RTP_CSRC_COUNT( octet1 );
+
+ /* Get the fields in the second octet */
+ octet2 = tvb_get_guint8( tvb, offset + 1 );
+ marker_set = RTP_MARKER( octet2 );
+ payload_type = RTP_PAYLOAD_TYPE( octet2 );
+
+ /* Save the payload type for Decode As */
+ p_add_proto_data(pinfo->pool, pinfo, proto_rtp, RTP_DECODE_AS_PROTO_DATA, GUINT_TO_POINTER(payload_type));
+
+ if (marker_set && payload_type >= FIRST_RTCP_CONFLICT_PAYLOAD_TYPE && payload_type <= LAST_RTCP_CONFLICT_PAYLOAD_TYPE) {
+ call_dissector(rtcp_handle, tvb, pinfo, tree);
+ return tvb_captured_length(tvb);
+ }
+
+ /* Get the subsequent fields */
+ seq_num = tvb_get_ntohs( tvb, offset + 2 );
+ timestamp = tvb_get_ntohl( tvb, offset + 4 );
+ sync_src = tvb_get_ntohl( tvb, offset + 8 );
+
+ /* fill in the rtp_info structure */
+ rtp_info->info_padding_set = padding_set;
+ rtp_info->info_marker_set = marker_set;
+ rtp_info->info_media_types = 0;
+ rtp_info->info_payload_type = payload_type;
+ rtp_info->info_seq_num = seq_num;
+ rtp_info->info_extended_seq_num = seq_num; /* initial with seq_number */
+ rtp_info->info_timestamp = timestamp;
+ rtp_info->info_extended_timestamp = timestamp; /* initial with timestamp */
+ rtp_info->info_sync_src = sync_src;
+ rtp_info->info_is_srtp = FALSE;
+ rtp_info->info_setup_frame_num = 0;
+ rtp_info->info_payload_type_str = NULL;
+ rtp_info->info_payload_rate = 0;
+ rtp_info->info_payload_fmtp_map = NULL;
+ rtp_info->info_is_ed137 = FALSE;
+ rtp_info->info_ed137_info = NULL;
+
+ /*
+ * Do we have all the data?
+ */
+ length = tvb_captured_length_remaining(tvb, offset);
+ reported_length = tvb_reported_length_remaining(tvb, offset);
+ if (reported_length >= 0 && length >= reported_length) {
+ /*
+ * Yes.
+ */
+ rtp_info->info_all_data_present = TRUE;
+ rtp_info->info_data_len = reported_length;
+
+ /*
+ * Save the pointer to raw rtp data (header + payload incl.
+ * padding).
+ * That should be safe because the "epan_dissect_t"
+ * constructed for the packet has not yet been freed when
+ * the taps are called.
+ * (Destroying the "epan_dissect_t" will end up freeing
+ * all the tvbuffs and hence invalidating pointers to
+ * their data.)
+ * See "add_packet_to_packet_list()" for details.
+ */
+ rtp_info->info_data = tvb_get_ptr(tvb, 0, -1);
+ } else {
+ /*
+ * No - packet was cut short at capture time.
+ */
+ rtp_info->info_all_data_present = FALSE;
+ rtp_info->info_data_len = 0;
+ rtp_info->info_data = NULL;
+ }
+
+ /* Look for conv and add to the frame if found */
+
+ p_packet_data = get_rtp_packet_info(pinfo, rtp_info);
+
+ if (p_packet_data && p_packet_data->srtp_info) is_srtp = TRUE;
+ rtp_info->info_is_srtp = is_srtp;
+
+ col_set_str( pinfo->cinfo, COL_PROTOCOL, (is_srtp) ? "SRTP" : "RTP" );
+
+#if 0 /* XXX: srtp_offset never actually used ?? */
+ /* check if this is added as an SRTP stream - if so, don't try to dissect the payload data for now */
+ if (p_conv_data && p_conv_data->srtp_info) {
+ srtp_info = p_conv_data->srtp_info;
+ if (rtp_info->info_all_data_present) {
+ srtp_offset = rtp_info->info_data_len - srtp_info->mki_len - srtp_info->auth_tag_len;
+ }
+ }
+#endif
+
+ if (p_packet_data && p_packet_data->bta2dp_info && p_packet_data->bta2dp_info->codec_dissector) {
+ rtp_info->info_payload_type_str = (const char *) dissector_handle_get_protocol_short_name(p_packet_data->bta2dp_info->codec_dissector);
+ } else if (p_packet_data && p_packet_data->btvdp_info && p_packet_data->btvdp_info->codec_dissector) {
+ rtp_info->info_payload_type_str = (const char *) dissector_handle_get_protocol_short_name(p_packet_data->btvdp_info->codec_dissector);
+ }
+
+ /* if it is dynamic payload, let use the conv data to see if it is defined */
+ if ( (payload_type>95) && (payload_type<128) ) {
+ if (p_packet_data && p_packet_data->rtp_dyn_payload) {
+ int sample_rate = 0;
+ unsigned channels = 1;
+ wmem_map_t *fmtp_map;
+
+#ifdef DEBUG_CONVERSATION
+ rtp_dump_dyn_payload(p_conv_data->rtp_dyn_payload);
+#endif
+ DPRINT(("looking up conversation data for dyn_pt=%d", payload_type));
+
+ if (rtp_dyn_payload_get_full(p_packet_data->rtp_dyn_payload, payload_type,
+ &payload_type_str, &sample_rate,
+ &channels, &fmtp_map)) {
+ DPRINT(("found conversation data for dyn_pt=%d, enc_name=%s",
+ payload_type, payload_type_str));
+ rtp_info->info_payload_type_str = payload_type_str;
+ rtp_info->info_payload_rate = sample_rate;
+ rtp_info->info_payload_channels = channels;
+ rtp_info->info_payload_fmtp_map = fmtp_map;
+ }
+ } else {
+ /* See if we have a dissector tied to the dynamic payload trough preferences*/
+ dissector_handle_t pt_dissector_handle;
+ const char *name;
+
+ pt_dissector_handle = dissector_get_uint_handle(rtp_pt_dissector_table, payload_type);
+ if (pt_dissector_handle) {
+ name = dissector_handle_get_dissector_name(pt_dissector_handle);
+ if (name) {
+ rtp_info->info_payload_type_str = name;
+ }
+ }
+ }
+ }
+
+ if (p_packet_data && p_packet_data->bta2dp_info) {
+ pt = (p_packet_data->bta2dp_info->codec_dissector) ? dissector_handle_get_protocol_short_name(p_packet_data->bta2dp_info->codec_dissector) : "Unknown";
+ } else if (p_packet_data && p_packet_data->btvdp_info) {
+ pt = (p_packet_data->btvdp_info->codec_dissector) ? dissector_handle_get_protocol_short_name(p_packet_data->btvdp_info->codec_dissector) : "Unknown";
+ } else {
+ pt = (payload_type_str ? payload_type_str : val_to_str_ext(payload_type, &rtp_payload_type_vals_ext, "Unknown (%u)"));
+ }
+
+ col_add_fstr( pinfo->cinfo, COL_INFO,
+ "PT=%s, SSRC=0x%X, Seq=%u, Time=%u%s",
+ pt,
+ sync_src,
+ seq_num,
+ timestamp,
+ marker_set ? ", Mark" : "");
+
+ if ( tree ) {
+ proto_tree *item;
+ /* Create RTP protocol tree */
+ ti = proto_tree_add_item(tree, proto_rtp, tvb, offset, -1, ENC_NA );
+ rtp_tree = proto_item_add_subtree(ti, ett_rtp );
+
+ /* Conversation setup info */
+ if (global_rtp_show_setup_info)
+ {
+ show_setup_info(tvb, pinfo, rtp_tree);
+ }
+
+ proto_tree_add_bitmask_list(rtp_tree, tvb, offset, 1, octet1_fields, ENC_NA);
+ offset++;
+
+ proto_tree_add_boolean( rtp_tree, hf_rtp_marker, tvb, offset,
+ 1, octet2 );
+
+ proto_tree_add_uint_format( rtp_tree, hf_rtp_payload_type, tvb,
+ offset, 1, octet2, "Payload type: %s (%u)", pt, payload_type);
+
+ offset++;
+
+ /* Sequence number 16 bits (2 octets) */
+ proto_tree_add_uint( rtp_tree, hf_rtp_seq_nr, tvb, offset, 2, seq_num );
+ if(p_packet_data != NULL) {
+ item = proto_tree_add_uint(rtp_tree, hf_rtp_ext_seq_nr, tvb, offset, 2, p_packet_data->extended_seqno);
+ proto_item_set_generated(item);
+ }
+ offset += 2;
+
+ /* Timestamp 32 bits (4 octets) */
+ proto_tree_add_uint( rtp_tree, hf_rtp_timestamp, tvb, offset, 4, timestamp );
+ offset += 4;
+
+ /* Synchronization source identifier 32 bits (4 octets) */
+ proto_tree_add_uint( rtp_tree, hf_rtp_ssrc, tvb, offset, 4, sync_src );
+ offset += 4;
+ } else {
+ offset += 12;
+ }
+ /* CSRC list*/
+ if ( csrc_count > 0 ) {
+ proto_tree *rtp_csrc_tree;
+ guint32 csrc_item;
+ ti = proto_tree_add_item(rtp_tree, hf_rtp_csrc_items, tvb, offset,
+ csrc_count * 4, ENC_NA);
+ proto_item_append_text(ti, " (%u items)", csrc_count);
+ rtp_csrc_tree = proto_item_add_subtree( ti, ett_csrc_list );
+
+ for (i = 0; i < csrc_count; i++ ) {
+ csrc_item = tvb_get_ntohl( tvb, offset );
+ proto_tree_add_uint_format( rtp_csrc_tree,
+ hf_rtp_csrc_item, tvb, offset, 4,
+ csrc_item,
+ "CSRC item %d: 0x%X",
+ i, csrc_item );
+ offset += 4;
+ }
+ }
+
+ /* Optional RTP header extension */
+ if ( extension_set ) {
+ unsigned int hdr_extension_len;
+ unsigned int hdr_extension_id;
+
+ /* Defined by profile field is 16 bits (2 octets) */
+ hdr_extension_id = tvb_get_ntohs( tvb, offset );
+ proto_tree_add_uint( rtp_tree, hf_rtp_prof_define, tvb, offset, 2, hdr_extension_id );
+ offset += 2;
+
+ hdr_extension_len = tvb_get_ntohs( tvb, offset );
+ proto_tree_add_uint( rtp_tree, hf_rtp_length, tvb, offset, 2, hdr_extension_len);
+ offset += 2;
+ if ( hdr_extension_len > 0 ) {
+ proto_tree *rtp_hext_tree = NULL;
+ tvbuff_t *newtvb;
+
+ ti = proto_tree_add_item(rtp_tree, hf_rtp_hdr_exts, tvb, offset, hdr_extension_len * 4, ENC_NA);
+ rtp_hext_tree = proto_item_add_subtree( ti, ett_hdr_ext );
+
+ /* pass interpretation of header extension to a registered subdissector */
+ newtvb = tvb_new_subset_length(tvb, offset, hdr_extension_len * 4);
+
+ if (hdr_extension_id == RTP_RFC5285_ONE_BYTE_SIG) {
+ dissect_rtp_hext_rfc5285_onebyte (newtvb, pinfo, rtp_hext_tree);
+ }
+ else if ((hdr_extension_id & RTP_RFC5285_TWO_BYTE_MASK) == RTP_RFC5285_TWO_BYTE_SIG) {
+ dissect_rtp_hext_rfc5285_twobytes(tvb,
+ offset - 4, hdr_extension_id, newtvb,
+ pinfo, rtp_hext_tree);
+ }
+ else {
+ if ( !(dissector_try_uint_new(rtp_hdr_ext_dissector_table, hdr_extension_id, newtvb, pinfo, rtp_hext_tree, FALSE, rtp_info)) ) {
+ unsigned int hdrext_offset;
+
+ hdrext_offset = offset;
+ for ( i = 0; i < hdr_extension_len; i++ ) {
+ proto_tree_add_item( rtp_hext_tree, hf_rtp_hdr_ext, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN );
+ hdrext_offset += 4;
+ }
+ }
+ }
+ }
+ offset += hdr_extension_len * 4;
+ }
+
+ if ( padding_set ) {
+ /*
+ * This RTP frame has padding - find it.
+ *
+ * The padding count is found in the LAST octet of
+ * the packet; it contains the number of octets
+ * that can be ignored at the end of the packet.
+ */
+ volatile unsigned int padding_count;
+ if (tvb_captured_length(tvb) < tvb_reported_length(tvb)) {
+ /*
+ * We don't *have* the last octet of the
+ * packet, so we can't get the padding
+ * count.
+ *
+ * Put an indication of that into the
+ * tree, and just put in a raw data
+ * item.
+ */
+ proto_tree_add_expert(rtp_tree, pinfo, &ei_rtp_padding_missing, tvb, 0, 0);
+ call_data_dissector(tvb_new_subset_remaining(tvb, offset),
+ pinfo, rtp_tree);
+ return tvb_captured_length(tvb);
+ }
+
+ padding_count = tvb_get_guint8( tvb,
+ tvb_reported_length( tvb ) - 1 );
+ data_len =
+ tvb_reported_length_remaining( tvb, offset ) - padding_count;
+
+ rtp_info->info_payload_offset = offset;
+
+ if (p_packet_data && p_packet_data->bta2dp_info) {
+ if (p_packet_data->bta2dp_info->codec_dissector == sbc_handle) {
+ rtp_info->info_payload_offset += 1;
+ }
+
+ if (p_packet_data->bta2dp_info->content_protection_type == BTAVDTP_CONTENT_PROTECTION_TYPE_SCMS_T) {
+ rtp_info->info_payload_offset += 1;
+ }
+ }
+
+ if (p_packet_data && p_packet_data->btvdp_info &&
+ p_packet_data->btvdp_info->content_protection_type == BTAVDTP_CONTENT_PROTECTION_TYPE_SCMS_T) {
+ rtp_info->info_payload_offset += 1;
+ }
+
+ rtp_info->info_payload_len = tvb_reported_length_remaining(tvb, rtp_info->info_payload_offset);
+
+ if (rtp_info->info_payload_len > padding_count) {
+ rtp_info->info_payload_len -= padding_count;
+ } else {
+ rtp_info->info_payload_len = 0;
+ }
+
+ if (data_len > 0) {
+ /*
+ * There's data left over when you take out
+ * the padding; dissect it.
+ */
+ struct _rtp_pkt_info *rtp_pkt_info = wmem_new(pinfo->pool, struct _rtp_pkt_info);
+
+ rtp_pkt_info->payload_len = data_len;
+ rtp_pkt_info->padding_len = padding_count - 1;
+ p_add_proto_data(pinfo->pool, pinfo, proto_rtp, pinfo->curr_layer_num, rtp_pkt_info);
+
+ /* Ensure that tap is called after packet dissection, even in case of exception */
+ TRY {
+ dissect_rtp_data( tvb, pinfo, tree, rtp_tree,
+ offset,
+ data_len,
+ data_len,
+ payload_type,
+ rtp_info);
+ } CATCH_ALL {
+ if (!pinfo->flags.in_error_pkt)
+ tap_queue_packet(rtp_tap, pinfo, rtp_info);
+ RETHROW;
+ }
+ ENDTRY;
+ offset += data_len;
+ } else if (data_len < 0) {
+ /*
+ * The padding count is bigger than the
+ * amount of RTP payload in the packet!
+ * Clip the padding count.
+ *
+ * XXX - put an item in the tree to indicate
+ * that the padding count is bogus?
+ */
+ padding_count =
+ tvb_reported_length_remaining(tvb, offset);
+ }
+ if (padding_count > 1) {
+ /*
+ * There's more than one byte of padding;
+ * show all but the last byte as padding
+ * data.
+ */
+ proto_tree_add_item( rtp_tree, hf_rtp_padding_data,
+ tvb, offset, padding_count - 1, ENC_NA );
+ offset += padding_count - 1;
+ }
+ /*
+ * Show the last byte in the PDU as the padding
+ * count.
+ */
+ proto_tree_add_item( rtp_tree, hf_rtp_padding_count,
+ tvb, offset, 1, ENC_BIG_ENDIAN );
+ }
+ else {
+ /*
+ * No padding.
+ */
+ rtp_info->info_payload_offset = offset;
+ rtp_info->info_payload_len = tvb_captured_length_remaining(tvb, offset);
+
+ if (p_packet_data && p_packet_data->bta2dp_info) {
+ if (p_packet_data->bta2dp_info->codec_dissector == sbc_handle) {
+ rtp_info->info_payload_offset += 1;
+ rtp_info->info_payload_len -= 1;
+ }
+
+ if (p_packet_data->bta2dp_info->content_protection_type == BTAVDTP_CONTENT_PROTECTION_TYPE_SCMS_T) {
+ rtp_info->info_payload_offset += 1;
+ rtp_info->info_payload_len -= 1;
+ }
+ }
+
+ if (p_packet_data && p_packet_data->btvdp_info &&
+ p_packet_data->btvdp_info->content_protection_type == BTAVDTP_CONTENT_PROTECTION_TYPE_SCMS_T) {
+ rtp_info->info_payload_offset += 1;
+ rtp_info->info_payload_len -= 1;
+ }
+
+ if (tvb_reported_length_remaining(tvb, offset) > 0) {
+ struct _rtp_pkt_info *rtp_pkt_info = wmem_new(pinfo->pool, struct _rtp_pkt_info);
+
+ rtp_pkt_info->payload_len = tvb_captured_length_remaining(tvb, offset);
+ rtp_pkt_info->padding_len = 0;
+ p_set_proto_data(pinfo->pool, pinfo, proto_rtp, pinfo->curr_layer_num, rtp_pkt_info);
+
+ /* Ensure that tap is called after packet dissection, even in case of exception */
+ TRY {
+ dissect_rtp_data( tvb, pinfo, tree, rtp_tree, offset,
+ tvb_captured_length_remaining( tvb, offset ),
+ tvb_reported_length_remaining( tvb, offset ),
+ payload_type, rtp_info);
+ } CATCH_ALL {
+ if (!pinfo->flags.in_error_pkt)
+ tap_queue_packet(rtp_tap, pinfo, rtp_info);
+ RETHROW;
+ }
+ ENDTRY;
+ }
+ }
+ if (!pinfo->flags.in_error_pkt)
+ tap_queue_packet(rtp_tap, pinfo, rtp_info);
+
+ return offset;
+}
+
+gint
+dissect_rtp_shim_header(tvbuff_t *tvb, gint start, packet_info *pinfo _U_, proto_tree *tree, struct _rtp_info *rtp_info)
+{
+ proto_item *rtp_ti = NULL;
+ proto_tree *rtp_tree = NULL;
+ proto_item *ti;
+ guint8 octet1, octet2;
+ unsigned int version;
+ gboolean padding_set;
+ gboolean extension_set;
+ unsigned int csrc_count;
+ gboolean marker_set;
+ unsigned int payload_type;
+ unsigned int i;
+ gint offset = start;
+ guint16 seq_num;
+ guint32 timestamp;
+ guint32 sync_src;
+ const char *pt = NULL;
+ static int * const octet1_fields[] = {
+ &hf_rtp_version,
+ &hf_rtp_padding,
+ &hf_rtp_extension,
+ &hf_rtp_csrc_count,
+ NULL
+ };
+
+ /* Get the fields in the first octet */
+ octet1 = tvb_get_guint8( tvb, offset );
+ version = RTP_VERSION( octet1 );
+
+ /* fill in the rtp_info structure */
+ if (rtp_info) rtp_info->info_version = version;
+ if (version != 2) {
+ /*
+ * Unknown or unsupported version.
+ */
+ if ( tree ) {
+ ti = proto_tree_add_item( tree, proto_rtp, tvb, offset, 1, ENC_NA );
+ rtp_tree = proto_item_add_subtree( ti, ett_rtp );
+
+ proto_tree_add_uint( rtp_tree, hf_rtp_version, tvb,
+ offset, 1, octet1);
+ }
+ return offset;
+ }
+
+ padding_set = RTP_PADDING( octet1 );
+ extension_set = RTP_EXTENSION( octet1 );
+ csrc_count = RTP_CSRC_COUNT( octet1 );
+
+ /* Get the fields in the second octet */
+ octet2 = tvb_get_guint8( tvb, offset + 1 );
+ marker_set = RTP_MARKER( octet2 );
+ payload_type = RTP_PAYLOAD_TYPE( octet2 );
+
+ /* Get the subsequent fields */
+ seq_num = tvb_get_ntohs( tvb, offset + 2 );
+ timestamp = tvb_get_ntohl( tvb, offset + 4 );
+ sync_src = tvb_get_ntohl( tvb, offset + 8 );
+
+ /* fill in the rtp_info structure */
+ if (rtp_info) {
+ rtp_info->info_padding_set = padding_set;
+ rtp_info->info_marker_set = marker_set;
+ rtp_info->info_media_types = 0;
+ rtp_info->info_payload_type = payload_type;
+ rtp_info->info_seq_num = seq_num;
+ rtp_info->info_timestamp = timestamp;
+ rtp_info->info_sync_src = sync_src;
+ rtp_info->info_data_len = 0;
+ rtp_info->info_all_data_present = FALSE;
+ rtp_info->info_payload_offset = 0;
+ rtp_info->info_payload_len = 0;
+ rtp_info->info_is_srtp = FALSE;
+ rtp_info->info_setup_frame_num = 0;
+ rtp_info->info_data = NULL;
+ rtp_info->info_payload_type_str = NULL;
+ rtp_info->info_payload_rate = 0;
+ rtp_info->info_payload_fmtp_map = NULL;
+ rtp_info->info_is_ed137 = FALSE;
+ rtp_info->info_ed137_info = NULL;
+ }
+
+ if ( tree ) {
+ /* Create RTP protocol tree */
+ rtp_ti = proto_tree_add_item(tree, proto_rtp, tvb, offset, 0, ENC_NA );
+ rtp_tree = proto_item_add_subtree(rtp_ti, ett_rtp );
+
+ proto_tree_add_bitmask_list(rtp_tree, tvb, offset, 1, octet1_fields, ENC_NA);
+ offset++;
+
+ proto_tree_add_boolean( rtp_tree, hf_rtp_marker, tvb, offset,
+ 1, octet2 );
+
+ pt = val_to_str_ext(payload_type, &rtp_payload_type_vals_ext, "Unknown (%u)");
+
+ proto_tree_add_uint_format( rtp_tree, hf_rtp_payload_type, tvb,
+ offset, 1, octet2, "Payload type: %s (%u)", pt, payload_type);
+
+ offset++;
+
+ /* Sequence number 16 bits (2 octets) */
+ proto_tree_add_uint( rtp_tree, hf_rtp_seq_nr, tvb, offset, 2, seq_num );
+ offset += 2;
+
+ /* Timestamp 32 bits (4 octets) */
+ proto_tree_add_uint( rtp_tree, hf_rtp_timestamp, tvb, offset, 4, timestamp );
+ offset += 4;
+
+ /* Synchronization source identifier 32 bits (4 octets) */
+ proto_tree_add_uint( rtp_tree, hf_rtp_ssrc, tvb, offset, 4, sync_src );
+ offset += 4;
+ } else {
+ offset += 12;
+ }
+ /* CSRC list*/
+ if ( csrc_count > 0 ) {
+ proto_tree *rtp_csrc_tree;
+ guint32 csrc_item;
+ ti = proto_tree_add_item(rtp_tree, hf_rtp_csrc_items, tvb, offset,
+ csrc_count * 4, ENC_NA);
+ proto_item_append_text(ti, " (%u items)", csrc_count);
+ rtp_csrc_tree = proto_item_add_subtree( ti, ett_csrc_list );
+
+ for (i = 0; i < csrc_count; i++ ) {
+ csrc_item = tvb_get_ntohl( tvb, offset );
+ proto_tree_add_uint_format( rtp_csrc_tree,
+ hf_rtp_csrc_item, tvb, offset, 4,
+ csrc_item,
+ "CSRC item %d: 0x%X",
+ i, csrc_item );
+ offset += 4;
+ }
+ }
+
+ /* Optional RTP header extension */
+ if ( extension_set ) {
+ unsigned int hdr_extension_len;
+ unsigned int hdr_extension_id;
+
+ /* Defined by profile field is 16 bits (2 octets) */
+ hdr_extension_id = tvb_get_ntohs( tvb, offset );
+ proto_tree_add_uint( rtp_tree, hf_rtp_prof_define, tvb, offset, 2, hdr_extension_id );
+ offset += 2;
+
+ hdr_extension_len = tvb_get_ntohs( tvb, offset );
+ proto_tree_add_uint( rtp_tree, hf_rtp_length, tvb, offset, 2, hdr_extension_len);
+ offset += 2;
+ if ( hdr_extension_len > 0 ) {
+ proto_tree *rtp_hext_tree = NULL;
+
+ ti = proto_tree_add_item(rtp_tree, hf_rtp_hdr_exts, tvb, offset, hdr_extension_len * 4, ENC_NA);
+ rtp_hext_tree = proto_item_add_subtree( ti, ett_hdr_ext );
+
+ for ( i = 0; i < hdr_extension_len; i++ ) {
+ proto_tree_add_item( rtp_hext_tree, hf_rtp_hdr_ext, tvb, offset, 4, ENC_BIG_ENDIAN );
+ offset += 4;
+ }
+ }
+ }
+
+ proto_item_set_len(rtp_ti, offset - start);
+
+ return (offset - start);
+}
+
+/* calculate the extended sequence number - top 16 bits of the previous sequence number,
+ * plus our own; then correct for wrapping */
+static guint32
+calculate_extended_seqno(guint32 previous_seqno, guint16 raw_seqno)
+{
+ guint32 seqno = (previous_seqno & 0xffff0000) | raw_seqno;
+ if (seqno + 0x8000 < previous_seqno) {
+ seqno += 0x10000;
+ } else if (previous_seqno + 0x8000 < seqno) {
+ /* we got an out-of-order packet which happened to go backwards over the
+ * wrap boundary */
+ seqno -= 0x10000;
+ }
+ return seqno;
+}
+
+/* calculate the extended sequence number - top 16 bits of the previous sequence number,
+ * plus our own; then correct for wrapping */
+static guint64
+calculate_extended_timestamp(guint64 previous_timestamp, guint32 raw_timestamp)
+{
+ guint64 timestamp = (previous_timestamp & 0xffffffff00000000) | raw_timestamp;
+ if (timestamp + 0x80000000 < previous_timestamp) {
+ timestamp += 0x100000000;
+ } else if (previous_timestamp + 0x80000000 < timestamp) {
+ /* we got an out-of-order packet which happened to go backwards over the
+ * wrap boundary */
+ timestamp -= 0x100000000;
+ }
+ return timestamp;
+}
+
+/* Look for conversation info */
+static struct _rtp_packet_info *
+get_rtp_packet_info(packet_info *pinfo, struct _rtp_info *rtp_info)
+{
+ /* Conversation and current data */
+ struct _rtp_packet_info *p_packet_data;
+
+ /* Use existing packet info if available */
+ p_packet_data = (struct _rtp_packet_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_rtp, RTP_CONVERSATION_PROTO_DATA);
+
+ if (!p_packet_data)
+ {
+ conversation_t *p_conv;
+
+ /* First time, get info from conversation */
+ p_conv = find_conversation(pinfo->num, &pinfo->net_dst, &pinfo->net_src,
+ conversation_pt_to_conversation_type(pinfo->ptype),
+ pinfo->destport, pinfo->srcport, NO_ADDR_B);
+ if (!p_conv) {
+ /* Create a conversation in case none exists (decode as is used for marking the packet as RTP) */
+ p_conv = conversation_new(pinfo->num, &pinfo->net_dst, &pinfo->net_src,
+ conversation_pt_to_conversation_type(pinfo->ptype),
+ pinfo->destport, pinfo->srcport, NO_ADDR2);
+ }
+
+ /* Create space for packet info */
+ struct _rtp_conversation_info *p_conv_data;
+ p_conv_data = (struct _rtp_conversation_info *)conversation_get_proto_data(p_conv, proto_rtp);
+
+ if (!p_conv_data) {
+ /* Create conversation data. If RTP was set up by an SDP or by
+ * the heuristic dissector, conversation data should already
+ * have been created. Therefore, we should only reach this
+ * case if Decode As is being used (See Issue #18829).
+ */
+ p_conv_data = wmem_new0(wmem_file_scope(), struct _rtp_conversation_info);
+ p_conv_data->ssrc_number_space = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
+ p_conv_data->rtp_conv_info = wmem_new(wmem_file_scope(), rtp_private_conv_info);
+ p_conv_data->rtp_conv_info->multisegment_pdus = wmem_tree_new(wmem_file_scope());
+ (void)g_strlcpy(p_conv_data->method, "DECODE AS", MAX_RTP_SETUP_METHOD_SIZE + 1);
+ p_conv_data->frame_number = pinfo->num;
+ p_conv_data->media_types = 0;
+ p_conv_data->srtp_info = NULL;
+ p_conv_data->bta2dp_info = NULL;
+ p_conv_data->btvdp_info = NULL;
+ conversation_add_proto_data(p_conv, proto_rtp, p_conv_data);
+ }
+
+ guint32 seqno;
+ guint64 timestamp;
+
+ /* Save this conversation info into packet info */
+ /* This is file scoped because we only do this on the first pass.
+ * On nonsequential passes, the conversation data has the values
+ * from the last dissected frame, which is not necessarily the
+ * immediately previous frame.
+ */
+ p_packet_data = wmem_new(wmem_file_scope(), struct _rtp_packet_info);
+ (void)g_strlcpy(p_packet_data->method, p_conv_data->method, MAX_RTP_SETUP_METHOD_SIZE + 1);
+ p_packet_data->frame_number = p_conv_data->frame_number;
+ p_packet_data->media_types = p_conv_data->media_types;
+ /* do not increment ref count for the rtp_dyn_payload */
+ p_packet_data->rtp_dyn_payload = p_conv_data->rtp_dyn_payload;
+ p_packet_data->rtp_conv_info = p_conv_data->rtp_conv_info;
+ p_packet_data->srtp_info = p_conv_data->srtp_info;
+ p_packet_data->rtp_sdp_setup_info_list = p_conv_data->rtp_sdp_setup_info_list;
+ p_packet_data->bta2dp_info = p_conv_data->bta2dp_info;
+ p_packet_data->btvdp_info = p_conv_data->btvdp_info;
+ p_add_proto_data(wmem_file_scope(), pinfo, proto_rtp, RTP_CONVERSATION_PROTO_DATA, p_packet_data);
+
+ rtp_number_space* number_space = wmem_map_lookup(p_conv_data->ssrc_number_space, GUINT_TO_POINTER(rtp_info->info_sync_src));
+ if (number_space == NULL) {
+ /* Start the extended numbers up one cycle, to cope gracefully
+ with the first few packets being out of order. */
+ number_space = wmem_new0(wmem_file_scope(), rtp_number_space);
+ number_space->extended_seqno = 0x10000;
+ number_space->extended_timestamp = 0x100000000;
+ wmem_map_insert(p_conv_data->ssrc_number_space, GUINT_TO_POINTER(rtp_info->info_sync_src), number_space);
+ }
+ /* calculate extended sequence number */
+ seqno = calculate_extended_seqno(number_space->extended_seqno,
+ rtp_info->info_seq_num);
+
+ p_packet_data->extended_seqno = seqno;
+ number_space->extended_seqno = seqno;
+
+ /* calculate extended timestamp */
+ timestamp = calculate_extended_timestamp(number_space->extended_timestamp,
+ rtp_info->info_timestamp);
+
+ p_packet_data->extended_timestamp = timestamp;
+ number_space->extended_timestamp = timestamp;
+ }
+ rtp_info->info_setup_frame_num = p_packet_data->frame_number;
+ rtp_info->info_media_types = p_packet_data->media_types;
+ rtp_info->info_extended_seq_num = p_packet_data->extended_seqno;
+ rtp_info->info_extended_timestamp = p_packet_data->extended_timestamp;
+ return p_packet_data;
+}
+
+
+/* Display setup info */
+static void
+show_setup_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ /* Conversation and current data */
+ struct _rtp_packet_info *p_packet_data;
+ proto_tree *rtp_setup_tree;
+ proto_item *ti;
+
+ /* Use existing packet info if available */
+ p_packet_data = (struct _rtp_packet_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_rtp, RTP_CONVERSATION_PROTO_DATA);
+
+ if (!p_packet_data) return;
+
+ /* Create setup info subtree with summary info. */
+ ti = proto_tree_add_string_format(tree, hf_rtp_setup, tvb, 0, 0,
+ "", "Stream setup by %s (frame %u)",
+ p_packet_data->method,
+ p_packet_data->frame_number);
+ proto_item_set_generated(ti);
+ rtp_setup_tree = proto_item_add_subtree(ti, ett_rtp_setup);
+ if (rtp_setup_tree)
+ {
+ /* Add details into subtree */
+ proto_item* item = proto_tree_add_uint(rtp_setup_tree, hf_rtp_setup_frame,
+ tvb, 0, 0, p_packet_data->frame_number);
+ proto_item_set_generated(item);
+ item = proto_tree_add_string(rtp_setup_tree, hf_rtp_setup_method,
+ tvb, 0, 0, p_packet_data->method);
+ proto_item_set_generated(item);
+
+ if (p_packet_data->rtp_sdp_setup_info_list){
+ guint i;
+ sdp_setup_info_t *stored_setup_info;
+ for (i = 0; i < wmem_array_get_count(p_packet_data->rtp_sdp_setup_info_list); i++) {
+ stored_setup_info = (sdp_setup_info_t *)wmem_array_index(p_packet_data->rtp_sdp_setup_info_list, i);
+ if (stored_setup_info->hf_id) {
+ if (stored_setup_info->hf_type == SDP_TRACE_ID_HF_TYPE_STR) {
+ item = proto_tree_add_string(rtp_setup_tree, stored_setup_info->hf_id, tvb, 0, 0, stored_setup_info->trace_id.str);
+ proto_item_set_generated(item);
+ if (stored_setup_info->add_hidden == TRUE) {
+ proto_item_set_hidden(item);
+ }
+ } else if (stored_setup_info->hf_type == SDP_TRACE_ID_HF_TYPE_GUINT32) {
+ item = proto_tree_add_uint(rtp_setup_tree, stored_setup_info->hf_id, tvb, 0, 0, stored_setup_info->trace_id.num);
+ proto_item_set_generated(item);
+ if (stored_setup_info->add_hidden == TRUE) {
+ proto_item_set_hidden(item);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/* Dissect PacketCable CCC header */
+
+static int
+dissect_pkt_ccc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
+{
+
+ if ( tree ) {
+ proto_item *ti;
+ proto_tree *pkt_ccc_tree;
+
+ ti = proto_tree_add_item(tree, proto_pkt_ccc, tvb, 0, 12, ENC_NA);
+ pkt_ccc_tree = proto_item_add_subtree(ti, ett_pkt_ccc);
+
+ proto_tree_add_item(pkt_ccc_tree, hf_pkt_ccc_id, tvb, 0, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(pkt_ccc_tree, hf_pkt_ccc_ts, tvb, 4, 8,
+ ENC_TIME_NTP|ENC_BIG_ENDIAN);
+ }
+
+ return dissect_rtp(tvb, pinfo, tree, data);
+}
+
+
+/* Register PacketCable CCC */
+
+void
+proto_register_pkt_ccc(void)
+{
+ static hf_register_info hf[] =
+ {
+ {
+ &hf_pkt_ccc_id,
+ {
+ "PacketCable CCC Identifier",
+ "pkt_ccc.ccc_id",
+ FT_UINT32,
+ BASE_DEC,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_pkt_ccc_ts,
+ {
+ "PacketCable CCC Timestamp",
+ "pkt_ccc.ts",
+ FT_ABSOLUTE_TIME,
+ ABSOLUTE_TIME_UTC,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+
+ };
+
+ static gint *ett[] =
+ {
+ &ett_pkt_ccc,
+ };
+
+ proto_pkt_ccc = proto_register_protocol("PacketCable Call Content Connection", "PKT CCC", "pkt_ccc");
+ proto_register_field_array(proto_pkt_ccc, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+
+ register_dissector("pkt_ccc", dissect_pkt_ccc, proto_pkt_ccc);
+}
+
+void
+proto_reg_handoff_pkt_ccc(void)
+{
+ /*
+ * Register this dissector as one that can be selected by a
+ * UDP port number.
+ */
+ dissector_handle_t pkt_ccc_handle;
+
+ pkt_ccc_handle = find_dissector("pkt_ccc");
+ dissector_add_for_decode_as_with_preference("udp.port", pkt_ccc_handle);
+}
+
+/* Register RTP */
+
+void
+proto_register_rtp(void)
+{
+ static hf_register_info hf[] =
+ {
+ {
+ &hf_rtp_version,
+ {
+ "Version",
+ "rtp.version",
+ FT_UINT8,
+ BASE_DEC,
+ VALS(rtp_version_vals),
+ 0xC0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_rtp_padding,
+ {
+ "Padding",
+ "rtp.padding",
+ FT_BOOLEAN,
+ 8,
+ NULL,
+ 0x20,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_rtp_extension,
+ {
+ "Extension",
+ "rtp.ext",
+ FT_BOOLEAN,
+ 8,
+ NULL,
+ 0x10,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_rtp_csrc_count,
+ {
+ "Contributing source identifiers count",
+ "rtp.cc",
+ FT_UINT8,
+ BASE_DEC,
+ NULL,
+ 0x0F,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_rtp_marker,
+ {
+ "Marker",
+ "rtp.marker",
+ FT_BOOLEAN,
+ 8,
+ NULL,
+ 0x80,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_rtp_payload_type,
+ {
+ "Payload type",
+ "rtp.p_type",
+ FT_UINT8,
+ BASE_DEC,
+ NULL,
+ 0x7F,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_rtp_seq_nr,
+ {
+ "Sequence number",
+ "rtp.seq",
+ FT_UINT16,
+ BASE_DEC,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_rtp_ext_seq_nr,
+ {
+ "Extended sequence number",
+ "rtp.extseq",
+ FT_UINT32,
+ BASE_DEC,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_rtp_timestamp,
+ {
+ "Timestamp",
+ "rtp.timestamp",
+ FT_UINT32,
+ BASE_DEC,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_rtp_ssrc,
+ {
+ "Synchronization Source identifier",
+ "rtp.ssrc",
+ FT_UINT32,
+ BASE_HEX_DEC,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_rtp_prof_define,
+ {
+ "Defined by profile",
+ "rtp.ext.profile",
+ FT_UINT16,
+ BASE_HEX_DEC | BASE_RANGE_STRING,
+ RVALS(rtp_ext_profile_rvals),
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_rtp_length,
+ {
+ "Extension length",
+ "rtp.ext.len",
+ FT_UINT16,
+ BASE_DEC,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_rtp_csrc_items,
+ {
+ "Contributing Source identifiers",
+ "rtp.csrc.items",
+ FT_NONE,
+ BASE_NONE,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_rtp_csrc_item,
+ {
+ "CSRC item",
+ "rtp.csrc.item",
+ FT_UINT32,
+ BASE_HEX_DEC,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_rtp_hdr_exts,
+ {
+ "Header extensions",
+ "rtp.hdr_exts",
+ FT_NONE,
+ BASE_NONE,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+/* Other RTP structures */
+ {
+ &hf_rtp_hdr_ext,
+ {
+ "Header extension",
+ "rtp.hdr_ext",
+ FT_UINT32,
+ BASE_HEX_DEC,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_rtp_data,
+ {
+ "Payload",
+ "rtp.payload",
+ FT_BYTES,
+ BASE_NONE,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_rtp_padding_data,
+ {
+ "Padding data",
+ "rtp.padding.data",
+ FT_BYTES,
+ BASE_NONE,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_rtp_padding_count,
+ {
+ "Padding count",
+ "rtp.padding.count",
+ FT_UINT8,
+ BASE_DEC,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_rtp_setup,
+ {
+ "Stream setup",
+ "rtp.setup",
+ FT_STRING,
+ BASE_NONE,
+ NULL,
+ 0x0,
+ "Stream setup, method and frame number", HFILL
+ }
+ },
+ {
+ &hf_rtp_setup_frame,
+ {
+ "Setup frame",
+ "rtp.setup-frame",
+ FT_FRAMENUM,
+ BASE_NONE,
+ NULL,
+ 0x0,
+ "Frame that set up this stream", HFILL
+ }
+ },
+ {
+ &hf_rtp_setup_method,
+ {
+ "Setup Method",
+ "rtp.setup-method",
+ FT_STRING,
+ BASE_NONE,
+ NULL,
+ 0x0,
+ "Method used to set up this stream", HFILL
+ }
+ },
+ {
+ &hf_rtp_rfc2198_follow,
+ {
+ "Follow",
+ "rtp.follow",
+ FT_BOOLEAN,
+ 8,
+ TFS(&tfs_set_notset),
+ 0x80,
+ "Next header follows", HFILL
+ }
+ },
+ {
+ &hf_rtp_rfc2198_tm_off,
+ {
+ "Timestamp offset",
+ "rtp.timestamp-offset",
+ FT_UINT16,
+ BASE_DEC,
+ NULL,
+ 0xFFFC,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_rtp_rfc2198_bl_len,
+ {
+ "Block length",
+ "rtp.block-length",
+ FT_UINT16,
+ BASE_DEC,
+ NULL,
+ 0x03FF,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_rtp_ext_rfc5285_id,
+ {
+ "Identifier",
+ "rtp.ext.rfc5285.id",
+ FT_UINT8,
+ BASE_DEC,
+ NULL,
+ 0x0,
+ "RFC 5285 Header Extension Identifier",
+ HFILL
+ }
+ },
+ {
+ &hf_rtp_ext_rfc5285_length,
+ {
+ "Length",
+ "rtp.ext.rfc5285.len",
+ FT_UINT8,
+ BASE_DEC,
+ NULL,
+ 0x0,
+ "RFC 5285 Header Extension length",
+ HFILL
+ }
+ },
+ {
+ &hf_rtp_ext_rfc5285_appbits,
+ {
+ "Application Bits",
+ "rtp.ext.rfc5285.appbits",
+ FT_UINT8,
+ BASE_DEC,
+ NULL,
+ 0x0,
+ "RFC 5285 2-bytes header application bits",
+ HFILL
+ }
+ },
+ {
+ &hf_rtp_ext_rfc5285_data,
+ {
+ "Extension Data",
+ "rtp.ext.rfc5285.data",
+ FT_BYTES,
+ BASE_NONE,
+ NULL,
+ 0x0,
+ "RFC 5285 Extension Data",
+ HFILL
+ }
+ },
+ {
+ &hf_rfc4571_header_len,
+ {
+ "RFC 4571 packet len",
+ "rtp.rfc4571.len",
+ FT_UINT16,
+ BASE_DEC,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+
+ /* reassembly stuff */
+ {&hf_rtp_fragments,
+ {"RTP Fragments", "rtp.fragments", FT_NONE, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+
+ {&hf_rtp_fragment,
+ {"RTP Fragment data", "rtp.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+
+ {&hf_rtp_fragment_overlap,
+ {"Fragment overlap", "rtp.fragment.overlap", FT_BOOLEAN, BASE_NONE,
+ NULL, 0x0, "Fragment overlaps with other fragments", HFILL }
+ },
+
+ {&hf_rtp_fragment_overlap_conflict,
+ {"Conflicting data in fragment overlap", "rtp.fragment.overlap.conflict",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "Overlapping fragments contained conflicting data", HFILL }
+ },
+
+ {&hf_rtp_fragment_multiple_tails,
+ {"Multiple tail fragments found", "rtp.fragment.multipletails",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "Several tails were found when defragmenting the packet", HFILL }
+ },
+
+ {&hf_rtp_fragment_too_long_fragment,
+ {"Fragment too long", "rtp.fragment.toolongfragment",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "Fragment contained data past end of packet", HFILL }
+ },
+
+ {&hf_rtp_fragment_error,
+ {"Defragmentation error", "rtp.fragment.error",
+ FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+ "Defragmentation error due to illegal fragments", HFILL }
+ },
+
+ {&hf_rtp_fragment_count,
+ {"Fragment count", "rtp.fragment.count",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+
+ {&hf_rtp_reassembled_in,
+ {"RTP fragment, reassembled in frame", "rtp.reassembled_in",
+ FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+ "This RTP packet is reassembled in this frame", HFILL }
+ },
+ {&hf_rtp_reassembled_length,
+ {"Reassembled RTP length", "rtp.reassembled.length",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "The total length of the reassembled payload", HFILL }
+ },
+ {&hf_srtp_encrypted_payload,
+ {"SRTP Encrypted Payload", "srtp.enc_payload",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+#if 0
+ {&hf_srtp_null_encrypted_payload,
+ {"SRTP Payload with NULL encryption", "srtp.null_enc_payload",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+#endif
+ {&hf_srtp_mki,
+ {"SRTP MKI", "srtp.mki",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ "SRTP Master Key Index", HFILL }
+ },
+ {&hf_srtp_auth_tag,
+ {"SRTP Auth Tag", "srtp.auth_tag",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ "SRTP Authentication Tag", HFILL }
+ }
+
+ };
+
+ static gint *ett[] =
+ {
+ &ett_rtp,
+ &ett_csrc_list,
+ &ett_hdr_ext,
+ &ett_hdr_ext_rfc5285,
+ &ett_rtp_setup,
+ &ett_rtp_rfc2198,
+ &ett_rtp_rfc2198_hdr,
+ &ett_rtp_fragment,
+ &ett_rtp_fragments
+ };
+
+ static ei_register_info ei[] = {
+ { &ei_rtp_fragment_unfinished, { "rtp.fragment_unfinished", PI_REASSEMBLE, PI_CHAT, "RTP fragment, unfinished", EXPFILL }},
+ { &ei_rtp_padding_missing, { "rtp.padding_missing", PI_MALFORMED, PI_ERROR, "Frame has padding, but not all the frame data was captured", EXPFILL }},
+ };
+
+ /* Decode As handling */
+ static build_valid_func rtp_da_build_value[1] = {rtp_value};
+ static decode_as_value_t rtp_da_values = {rtp_prompt, 1, rtp_da_build_value};
+ static decode_as_t rtp_da = {"rtp", "rtp.pt", 1, 0, &rtp_da_values, NULL, NULL,
+ decode_as_default_populate_list, decode_as_default_reset, decode_as_default_change, NULL};
+
+ module_t *rtp_module;
+ expert_module_t *expert_rtp;
+
+ proto_rtp = proto_register_protocol("Real-Time Transport Protocol", "RTP", "rtp");
+ proto_rtp_rfc2198 = proto_register_protocol_in_name_only("RTP Payload for Redundant Audio Data (RFC 2198)",
+ "RAD (RFC2198)", "rtp_rfc2198", proto_rtp, FT_PROTOCOL);
+
+ proto_register_field_array(proto_rtp, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+ expert_rtp = expert_register_protocol(proto_rtp);
+ expert_register_field_array(expert_rtp, ei, array_length(ei));
+
+ rtp_handle = register_dissector("rtp", dissect_rtp, proto_rtp);
+ rtp_rfc2198_handle = register_dissector("rtp.rfc2198", dissect_rtp_rfc2198, proto_rtp_rfc2198);
+ rtp_rfc4571_handle = register_dissector("rtp.rfc4571", dissect_rtp_rfc4571, proto_rtp);
+
+ rtp_tap = register_tap("rtp");
+
+ rtp_pt_dissector_table = register_dissector_table("rtp.pt",
+ "RTP payload type", proto_rtp, FT_UINT8, BASE_DEC);
+ rtp_dyn_pt_dissector_table = register_dissector_table("rtp_dyn_payload_type",
+ "Dynamic RTP payload type", proto_rtp, FT_STRING, STRING_CASE_INSENSITIVE);
+
+
+ rtp_hdr_ext_dissector_table = register_dissector_table("rtp.hdr_ext",
+ "RTP header extension", proto_rtp, FT_UINT32, BASE_HEX);
+ rtp_hdr_ext_rfc5285_dissector_table = register_dissector_table("rtp.ext.rfc5285.id",
+ "RTP Generic header extension (RFC 5285)", proto_rtp, FT_UINT8, BASE_DEC);
+
+ rtp_module = prefs_register_protocol(proto_rtp, NULL);
+
+ prefs_register_bool_preference(rtp_module, "show_setup_info",
+ "Show stream setup information",
+ "Where available, show which protocol and frame caused "
+ "this RTP stream to be created",
+ &global_rtp_show_setup_info);
+
+ prefs_register_obsolete_preference(rtp_module, "heuristic_rtp");
+
+ prefs_register_bool_preference(rtp_module, "desegment_rtp_streams",
+ "Allow subdissector to reassemble RTP streams",
+ "Whether subdissector can request RTP streams to be reassembled",
+ &desegment_rtp);
+
+ prefs_register_enum_preference(rtp_module, "version0_type",
+ "Treat RTP version 0 packets as",
+ "If an RTP version 0 packet is encountered, it can be treated as "
+ "an invalid or ZRTP packet, a CLASSIC-STUN packet, or a T.38 packet",
+ &global_rtp_version0_type,
+ rtp_version0_types, FALSE);
+ prefs_register_obsolete_preference(rtp_module, "rfc2198_payload_type");
+
+ prefs_register_bool_preference(rtp_module, "rfc2198_deencapsulate",
+ "De-encapsulate RFC 2198 primary encoding",
+ "De-encapsulate the primary encoding from "
+ "the RAD header for RTP analysis and "
+ "playback",
+ &rfc2198_deencapsulate);
+
+ reassembly_table_register(&rtp_reassembly_table,
+ &addresses_reassembly_table_functions);
+
+ register_init_routine(rtp_dyn_payloads_init);
+ register_decode_as(&rtp_da);
+}
+
+void
+proto_reg_handoff_rtp(void)
+{
+ dissector_add_for_decode_as("udp.port", rtp_handle);
+ dissector_add_for_decode_as("tcp.port", rtp_rfc4571_handle);
+ dissector_add_string("rtp_dyn_payload_type", "red", rtp_rfc2198_handle);
+ heur_dissector_add( "udp", dissect_rtp_heur, "RTP over UDP", "rtp_udp", proto_rtp, HEURISTIC_DISABLE);
+ heur_dissector_add("stun", dissect_rtp_heur, "RTP over TURN", "rtp_stun", proto_rtp, HEURISTIC_DISABLE);
+ heur_dissector_add("classicstun", dissect_rtp_heur, "RTP over CLASSICSTUN", "rtp_classicstun", proto_rtp, HEURISTIC_DISABLE);
+ heur_dissector_add("rtsp", dissect_rtp_heur, "RTP over RTSP", "rtp_rtsp", proto_rtp, HEURISTIC_DISABLE);
+
+ dissector_add_for_decode_as("flip.payload", rtp_handle );
+
+
+ rtcp_handle = find_dissector_add_dependency("rtcp", proto_rtp);
+ stun_handle = find_dissector_add_dependency("stun-udp", proto_rtp);
+ classicstun_handle = find_dissector_add_dependency("classicstun", proto_rtp);
+ classicstun_heur_handle = find_dissector_add_dependency("classicstun-heur", proto_rtp);
+ stun_heur_handle = find_dissector_add_dependency("stun-heur", proto_rtp);
+ t38_handle = find_dissector_add_dependency("t38_udp", proto_rtp);
+ zrtp_handle = find_dissector_add_dependency("zrtp", proto_rtp);
+ dtls_handle = find_dissector_add_dependency("dtls", proto_rtp);
+
+ sprt_handle = find_dissector_add_dependency("sprt", proto_rtp);
+ v150fw_handle = find_dissector("v150fw");
+
+ bta2dp_content_protection_header_scms_t = find_dissector_add_dependency("bta2dp_content_protection_header_scms_t", proto_rtp);
+ btvdp_content_protection_header_scms_t = find_dissector_add_dependency("btvdp_content_protection_header_scms_t", proto_rtp);
+ bta2dp_handle = find_dissector_add_dependency("bta2dp", proto_rtp);
+ btvdp_handle = find_dissector_add_dependency("btvdp", proto_rtp);
+ sbc_handle = find_dissector_add_dependency("sbc", proto_rtp);
+
+ dissector_add_string("rtp_dyn_payload_type", "v150fw", v150fw_handle);
+ dissector_add_for_decode_as("rtp.pt", v150fw_handle);
+
+ dissector_add_for_decode_as("btl2cap.cid", rtp_handle);
+
+ dissector_add_uint_range_with_preference("rtp.pt", RFC2198_DEFAULT_PT_RANGE, rtp_rfc2198_handle);
+ proto_sdp = proto_get_id_by_filter_name("sdp");
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */