wireshark/epan/dissectors/packet-rtp.c

3338 lines
93 KiB
C

/* 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>
*
* $Id$
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* This dissector tries to dissect the RTP protocol according to Annex A
* of ITU-T Recommendation H.225.0 (02/98) or RFC 1889
*
* RTP traffic is 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
*
* 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 "packet-rtp.h"
#include <epan/rtp_pt.h>
#include <epan/conversation.h>
#include <epan/reassemble.h>
#include <epan/tap.h>
#include <epan/epan_dissect.h>
#include <epan/prefs.h>
#include <epan/wmem/wmem.h>
#include <epan/strutil.h>
/* uncomment this to enable debugging of fragment reassembly */
/* #define DEBUG_FRAGMENTS 1 */
typedef struct _rfc2198_hdr {
unsigned int pt;
int offset;
int len;
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;
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 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 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;
/* RTP header fields */
static int proto_rtp = -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 header ED137A extension fields */
static int hf_rtp_hdr_ed137s = -1;
static int hf_rtp_hdr_ed137 = -1;
static int hf_rtp_hdr_ed137a = -1;
static int hf_rtp_hdr_ed137_ptt_type = -1;
static int hf_rtp_hdr_ed137_squ = -1;
static int hf_rtp_hdr_ed137_ptt_id = -1;
static int hf_rtp_hdr_ed137_sct = -1;
static int hf_rtp_hdr_ed137_x = -1;
static int hf_rtp_hdr_ed137_x_nu = -1;
static int hf_rtp_hdr_ed137_ft_type = -1;
static int hf_rtp_hdr_ed137_ft_len = -1;
static int hf_rtp_hdr_ed137_ft_value = -1;
static int hf_rtp_hdr_ed137_ft_bss_qidx = -1;
static int hf_rtp_hdr_ed137_ft_bss_rssi_qidx = -1;
static int hf_rtp_hdr_ed137_ft_bss_qidx_ml = -1;
static int hf_rtp_hdr_ed137_ft_bss_nu = -1;
static int hf_rtp_hdr_ed137_vf = -1;
static int hf_rtp_hdr_ed137a_ptt_type = -1;
static int hf_rtp_hdr_ed137a_squ = -1;
static int hf_rtp_hdr_ed137a_ptt_id = -1;
static int hf_rtp_hdr_ed137a_pm = -1;
static int hf_rtp_hdr_ed137a_ptts = -1;
static int hf_rtp_hdr_ed137a_sct = -1;
static int hf_rtp_hdr_ed137a_reserved = -1;
static int hf_rtp_hdr_ed137a_x = -1;
static int hf_rtp_hdr_ed137a_x_nu = -1;
static int hf_rtp_hdr_ed137a_ft_type = -1;
static int hf_rtp_hdr_ed137a_ft_len = -1;
static int hf_rtp_hdr_ed137a_ft_value = -1;
static gint ett_hdr_ext_ed137s = -1;
static gint ett_hdr_ext_ed137 = -1;
static gint ett_hdr_ext_ed137a = -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_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;
/* PacketCable CCC port preference */
static guint global_pkt_ccc_udp_port = 0;
/* 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;
#define RTP0_INVALID 0
#define RTP0_STUN 1
#define RTP0_CLASSICSTUN 2
#define RTP0_T38 3
#define RTP0_SPRT 4
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 },
{ NULL, NULL, 0 }
};
static gint global_rtp_version0_type = 0;
static dissector_handle_t data_handle;
/* 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 void get_conv_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;
/* Try heuristic RTP decode */
static gboolean global_rtp_heur = FALSE;
/* desegment RTP streams */
static gboolean desegment_rtp = TRUE;
/* RFC2198 Redundant Audio Data */
static guint rtp_rfc2198_pt = 99;
/*
* 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
/* ED137 PTT */
#define RTP_ED137_ptt_mask(octet) ((octet) & 0xE0000000)
#define RTP_ED137A_ptt_mask(octet) ((octet) & 0xE0000000)
#define RTP_ED137_squ_mask(octet) ((octet) & 0x10000000)
#define RTP_ED137A_squ_mask(octet) ((octet) & 0x10000000)
/* ED137 extended information */
#define RTP_ED137_extended_information(octet) ((octet) & 0x00400000)
#define RTP_ED137A_extended_information(octet) ((octet) & 0x00010000)
/* ED137 feature type */
#define RTP_ED137_feature_type(octet) (((octet) & 0x003C0000) >> 18)
#define RTP_ED137A_feature_type(octet) (((octet) & 0x0000F000) >> 12)
/* ED137 feature length */
#define RTP_ED137_feature_length(octet) (((octet) & 0x0003C000) >> 14)
#define RTP_ED137A_feature_length(octet) (((octet) & 0x00000F00) >> 8)
/* ED137 feature value */
#define RTP_ED137_feature_value(octet) (((octet) & 0x00003FFE) >> 1)
#define RTP_ED137A_feature_value(octet) (((octet) & 0x000000FF) >> 0)
/* ED137 BSS constants */
#define RTP_ED137_feature_bss_type 0x1
#define RTP_ED137_feature_bss_len 11
#define RTP_ED137_feature_bss_qidx(octet) (((octet) & 0x00003FC0) >> 6)
#define RTP_ED137_feature_bss_qidx_ml(octet) (((octet) & 0x00000038) >> 2)
/* RFC 5215 one byte header signature */
#define RTP_RFC5215_ONE_BYTE_SIG 0xBEDE
/* RFC 5215 two byte header mask and signature */
#define RTP_RFC5215_TWO_BYTE_MASK 0xFFF0
#define RTP_RFC5215_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 value_string rtp_ext_profile_vals[] =
{
{ RTP_ED137_SIG, "ED137" },
{ RTP_ED137A_SIG, "ED137A" },
{ 0, NULL },
};
static const value_string rtp_ext_ed137_ptt_type[] =
{
{ 0x00, "PTT OFF" },
{ 0x01, "Normal PTT ON" },
{ 0x02, "Coupling PTT ON" },
{ 0x03, "Priority PTT ON" },
{ 0x04, "Emergency PTT ON" },
{ 0x05, "Reserved" },
{ 0x06, "Reserved" },
{ 0x07, "Reserved" },
{ 0, NULL },
};
static const value_string rtp_ext_ed137_squ[] =
{
{ 0x00, "SQ OFF" },
{ 0x01, "SQ ON" },
{ 0, NULL },
};
static const value_string rtp_ext_ed137_ft_type[] =
{
{ 0x0, "No features" },
{ 0x1, "Best signal selection" },
{ 0x2, "CLIMAX time delay" },
{ 0x3, "Reserved" },
{ 0x4, "Reserved" },
{ 0x5, "Reserved" },
{ 0x6, "Reserved" },
{ 0x7, "Reserved" },
{ 0x8, "Reserved" },
{ 0x9, "Reserved" },
{ 0xA, "Reserved" },
{ 0xB, "Vendor reserved" },
{ 0xC, "Vendor reserved" },
{ 0xD, "Vendor reserved" },
{ 0xE, "Vendor reserved" },
{ 0xF, "Vendor reserved" },
{ 0, NULL },
};
static const value_string rtp_ext_ed137_vf[] =
{
{ 0x00, "VF OFF" },
{ 0x01, "VF ON" },
{ 0, NULL },
};
static const value_string rtp_ext_ed137_ft_bss_rssi_qidx[] =
{
{ 0x00, "lower than -100.00 dBm" },
{ 0x01, "lower than or equal to -97.86 dBm" },
{ 0x02, "lower than or equal to -95.71 dBm" },
{ 0x03, "lower than or equal to -93.57 dBm" },
{ 0x04, "lower than or equal to -91.43 dBm" },
{ 0x05, "lower than or equal to -89.29 dBm" },
{ 0x06, "lower than or equal to -87.14 dBm" },
{ 0x07, "lower than or equal to -85.00 dBm" },
{ 0x08, "lower than or equal to -82.86 dBm" },
{ 0x09, "lower than or equal to -80.71 dBm" },
{ 0x0a, "lower than or equal to -78.57 dBm" },
{ 0x0b, "lower than or equal to -76.43 dBm" },
{ 0x0c, "lower than or equal to -74.29 dBm" },
{ 0x0d, "lower than or equal to -72.14 dBm" },
{ 0x0e, "lower than or equal to -70.00 dBm" },
{ 0x0f, "higher than -70.00 dBm" },
{ 0, NULL },
};
static const value_string rtp_ext_ed137_ft_bss_qidx_ml[] =
{
{ 0x00, "RSSI" },
{ 0x01, "AGC Level" },
{ 0x02, "C/N" },
{ 0x03, "Standardized PSD" },
{ 0x04, "Vendor specific method" },
{ 0x05, "Vendor specific method" },
{ 0x06, "Vendor specific method" },
{ 0x07, "Vendor specific method" },
{ 0, NULL },
};
static const value_string rtp_ext_ed137a_ptt_type[] =
{
{ 0x00, "PTT OFF" },
{ 0x01, "Normal PTT ON" },
{ 0x02, "Coupling PTT ON" },
{ 0x03, "Priority PTT ON" },
{ 0x04, "Emergency PTT ON" },
{ 0x05, "Reserved" },
{ 0x06, "Reserved" },
{ 0x07, "Reserved" },
{ 0, NULL },
};
static const value_string rtp_ext_ed137a_squ[] =
{
{ 0x00, "SQ OFF" },
{ 0x01, "SQ ON" },
{ 0, NULL },
};
static const value_string rtp_ext_ed137a_ft_type[] =
{
{ 0x0, "No features" },
{ 0x1, "Signal Quality Information" },
{ 0x2, "CLIMAX time delay" },
{ 0x3, "Radio remote control" },
{ 0x4, "CLIMAX dynamic delay compensation" },
{ 0x5, "Reserved" },
{ 0x6, "Reserved" },
{ 0x7, "Reserved" },
{ 0x8, "Reserved" },
{ 0x9, "Reserved" },
{ 0xA, "Reserved" },
{ 0xB, "Vendor reserved" },
{ 0xC, "Vendor reserved" },
{ 0xD, "Vendor reserved" },
{ 0xE, "Vendor reserved" },
{ 0xF, "Vendor reserved" },
{ 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)
/* http://www.iana.org/assignments/rtp-parameters */
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 ? */
/* 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 addtional 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 ? */
{ 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
/* initialisation routine */
static void
rtp_fragment_init(void)
{
reassembly_table_init(&rtp_reassembly_table,
&addresses_reassembly_table_functions);
}
void
rtp_free_hash_dyn_payload(GHashTable *rtp_dyn_payload)
{
if (rtp_dyn_payload == NULL) return;
g_hash_table_destroy(rtp_dyn_payload);
rtp_dyn_payload = NULL;
}
void
bluetooth_add_address(packet_info *pinfo, address *addr,
const gchar *setup_method, guint32 setup_frame_number,
gboolean is_video, 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->flags.visited)
{
return;
}
SET_ADDRESS(&null_addr, AT_NONE, 0, NULL);
/*
* 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, PT_BLUETOOTH, 0, 0,
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, PT_BLUETOOTH, 0, 0,
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_new(wmem_file_scope(), struct _rtp_conversation_info);
p_conv_data->rtp_dyn_payload = NULL;
/* start this at 0x10000 so that we cope gracefully with the
* first few packets being out of order (hence 0,65535,1,2,...)
*/
p_conv_data->extended_seqno = 0x10000;
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 (is_video) {
p_conv_data->bta2dp_info = NULL;
p_conv_data->btvdp_info = (btvdp_codec_info_t *) wmem_memdup(wmem_file_scope(), data, sizeof(btvdp_codec_info_t));
} else {
p_conv_data->bta2dp_info = (bta2dp_codec_info_t *) wmem_memdup(wmem_file_scope(), data, sizeof(bta2dp_codec_info_t));
p_conv_data->btvdp_info = NULL;
}
}
/*
* Update the conversation data.
*/
/* Free the hash if already exists */
rtp_free_hash_dyn_payload(p_conv_data->rtp_dyn_payload);
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->is_video = is_video;
p_conv_data->rtp_dyn_payload = NULL;
p_conv_data->srtp_info = NULL;
}
/* Set up an SRTP conversation */
void
srtp_add_address(packet_info *pinfo, address *addr, int port, int other_port,
const gchar *setup_method, guint32 setup_frame_number,
gboolean is_video _U_, GHashTable *rtp_dyn_payload,
struct srtp_info *srtp_info)
{
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->flags.visited)
{
return;
}
#ifdef DEBUG
printf("#%u: %srtp_add_address(%s, %u, %u, %s, %u\n",
pinfo->fd->num, (srtp_info)?"s":"", ep_address_to_str(addr), port,
other_port, setup_method, setup_frame_number);
#endif
SET_ADDRESS(&null_addr, AT_NONE, 0, NULL);
/*
* 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, PT_UDP, port, other_port,
NO_ADDR_B | (!other_port ? NO_PORT_B : 0));
/*
* 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, PT_UDP,
(guint32)port, (guint32)other_port,
NO_ADDR2 | (!other_port ? NO_PORT2 : 0));
}
/* 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_new(wmem_file_scope(), struct _rtp_conversation_info);
p_conv_data->rtp_dyn_payload = NULL;
/* start this at 0x10000 so that we cope gracefully with the
* first few packets being out of order (hence 0,65535,1,2,...)
*/
p_conv_data->extended_seqno = 0x10000;
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);
}
/*
* Update the conversation data.
*/
/* Free the hash if already exists */
rtp_free_hash_dyn_payload(p_conv_data->rtp_dyn_payload);
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->is_video = is_video;
p_conv_data->rtp_dyn_payload = rtp_dyn_payload;
p_conv_data->srtp_info = srtp_info;
p_conv_data->bta2dp_info = NULL;
p_conv_data->btvdp_info = NULL;
}
/* Set up an RTP conversation */
void
rtp_add_address(packet_info *pinfo, address *addr, int port, int other_port,
const gchar *setup_method, guint32 setup_frame_number,
gboolean is_video , GHashTable *rtp_dyn_payload)
{
srtp_add_address(pinfo, addr, port, other_port, setup_method, setup_frame_number, is_video, rtp_dyn_payload, NULL);
}
static gboolean
dissect_rtp_heur_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, gboolean check_destport)
{
guint8 octet1;
unsigned int version;
unsigned int offset = 0;
/* This is a heuristic dissector, which means we get all the UDP
* traffic not sent to a known dissector and not claimed by
* a heuristic dissector called before us!
*/
if (! global_rtp_heur)
return FALSE;
/* Get the fields in the first octet */
octet1 = tvb_get_guint8( tvb, offset );
version = RTP_VERSION( octet1 );
if (version == 0) {
if (!(tvb_memeql(tvb, 4, "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:
default:
return FALSE; /* Unknown or unsupported version */
}
}
} else if (version != 2) {
/* Unknown or unsupported version */
return FALSE;
}
/* Was it sent to an even-numbered port? */
if (check_destport && ((pinfo->destport % 2) != 0)) {
return FALSE;
}
dissect_rtp( tvb, pinfo, tree, data );
return TRUE;
}
static gboolean
dissect_rtp_heur_udp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data )
{
return dissect_rtp_heur_common(tvb, pinfo, tree, data, TRUE);
}
static gboolean
dissect_rtp_heur_stun( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data )
{
return dissect_rtp_heur_common(tvb, pinfo, tree, data, FALSE);
}
/*
* 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_conversation_info *p_conv_data = NULL;
gboolean found_match = FALSE;
int payload_len;
struct srtp_info *srtp_info;
int offset = 0;
payload_len = tvb_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_conv_data = (struct _rtp_conversation_info *)p_get_proto_data(pinfo->fd, proto_rtp, 0);
if (p_conv_data && p_conv_data->srtp_info) {
srtp_info = p_conv_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_text(rtp_tree, newtvb, offset, payload_len, "SRTP Payload with NULL encryption");
}
else
#endif
{
if (rtp_tree)
proto_tree_add_item(rtp_tree, hf_srtp_encrypted_payload, newtvb, offset, payload_len, ENC_NA);
found_match = TRUE; /* use this flag to prevent dissection below */
}
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;*/
}
} else if (p_conv_data && !p_conv_data->bta2dp_info && !p_conv_data->btvdp_info &&
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_conv_data && p_conv_data->rtp_dyn_payload) {
gchar *payload_type_str = NULL;
encoding_name_and_rate_t *encoding_name_and_rate_pt = NULL;
encoding_name_and_rate_pt = (encoding_name_and_rate_t *)g_hash_table_lookup(p_conv_data->rtp_dyn_payload, &payload_type);
if (encoding_name_and_rate_pt) {
payload_type_str = encoding_name_and_rate_pt->encoding_name;
}
if (payload_type_str){
found_match = dissector_try_string(rtp_dyn_pt_dissector_table,
payload_type_str, newtvb, pinfo, tree, NULL);
/* 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(found_match==FALSE)
proto_tree_add_item( rtp_tree, hf_rtp_data, newtvb, 0, -1, ENC_NA );
return;
}
}
} else if (p_conv_data && p_conv_data->bta2dp_info) {
tvbuff_t *nexttvb;
gint suboffset = 0;
found_match = TRUE;
if (p_conv_data->bta2dp_info->content_protection_type == BTAVDTP_CONTENT_PROTECTION_TYPE_SCMS_T) {
nexttvb = tvb_new_subset(newtvb, 0, 1, 1);
call_dissector(bta2dp_content_protection_header_scms_t, nexttvb, pinfo, tree);
suboffset = 1;
}
nexttvb = tvb_new_subset_remaining(newtvb, suboffset);
if (p_conv_data->bta2dp_info->codec_dissector)
call_dissector(p_conv_data->bta2dp_info->codec_dissector, nexttvb, pinfo, tree);
else
call_dissector(data_handle, nexttvb, pinfo, tree);
} else if (p_conv_data && p_conv_data->btvdp_info) {
tvbuff_t *nexttvb;
gint suboffset = 0;
found_match = TRUE;
if (p_conv_data->btvdp_info->content_protection_type == BTAVDTP_CONTENT_PROTECTION_TYPE_SCMS_T) {
nexttvb = tvb_new_subset(newtvb, 0, 1, 1);
call_dissector(bta2dp_content_protection_header_scms_t, nexttvb, pinfo, tree);
suboffset = 1;
}
nexttvb = tvb_new_subset_remaining(newtvb, suboffset);
if (p_conv_data->btvdp_info->codec_dissector)
call_dissector(p_conv_data->btvdp_info->codec_dissector, nexttvb, pinfo, tree);
else
call_dissector(data_handle, nexttvb, pinfo, tree);
}
/* if we don't found, it is static OR could be set static from the preferences */
if (!found_match && !dissector_try_uint(rtp_pt_dissector_table, payload_type, newtvb, pinfo, tree))
proto_tree_add_item( rtp_tree, hf_rtp_data, newtvb, 0, -1, ENC_NA );
}
/* 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)
{
tvbuff_t *newtvb;
struct _rtp_conversation_info *p_conv_data= NULL;
gboolean must_desegment = FALSE;
rtp_private_conv_info *finfo = NULL;
rtp_multisegment_pdu *msp = NULL;
guint32 seqno;
/* Retrieve RTPs idea of a converation */
p_conv_data = (struct _rtp_conversation_info *)p_get_proto_data(pinfo->fd, proto_rtp, 0);
if(p_conv_data != NULL)
finfo = p_conv_data->rtp_conv_info;
if(finfo == NULL || !desegment_rtp) {
/* Hand the whole lot off to the subdissector */
newtvb=tvb_new_subset(tvb,offset,data_len,data_reported_len);
process_rtp_payload(newtvb, pinfo, tree, rtp_tree, payload_type);
return;
}
seqno = p_conv_data->extended_seqno;
pinfo->can_desegment = 2;
pinfo->desegment_offset = 0;
pinfo->desegment_len = 0;
#ifdef DEBUG_FRAGMENTS
g_debug("%d: RTP Part of convo %d(%p); seqno %d",
pinfo->fd->num,
p_conv_data->frame_number, p_conv_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
g_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
g_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);
/*
* Check to see if there were any complete fragments within the chunk
*/
if( pinfo->desegment_len && pinfo->desegment_offset == 0 )
{
#ifdef DEBUG_FRAGMENTS
g_debug("\tNo complete pdus in payload" );
#endif
/* Mark the fragments and 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;
}
else
{
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;
}
}
}
}
else
{
/*
* The segment is not the continuation of a fragmented segment
* so process it as normal
*/
#ifdef DEBUG_FRAGMENTS
g_debug("\tRTP non-fragment payload");
#endif
newtvb = tvb_new_subset( tvb, offset, data_len, data_reported_len );
/* Hand off to the subdissector */
process_rtp_payload(newtvb, pinfo, tree, rtp_tree, payload_type);
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 = NULL;
#ifdef DEBUG_FRAGMENTS
g_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->flags.visited,
frag_len,
deseg_offset);
#endif
/* allocate a new msp for this pdu */
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
g_debug("\tReassembled in %d", fd_head->reassembled_in);
#endif
}
else
{
#ifdef DEBUG_FRAGMENTS
g_debug("\tUnfinished fragment");
#endif
/* this fragment is never reassembled */
proto_tree_add_text( tree, tvb, deseg_offset, -1,"RTP fragment, unfinished");
}
}
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
g_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]");
}
}
pinfo->can_desegment = 0;
pinfo->desegment_offset = 0;
pinfo->desegment_len = 0;
}
static void
dissect_rtp_rfc2198(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
gint offset = 0;
guint8 octet1;
int cnt;
gboolean hdr_follow = TRUE;
proto_item *ti = NULL;
proto_tree *rfc2198_tree = NULL;
proto_tree *rfc2198_hdr_tree = NULL;
rfc2198_hdr *hdr_last, *hdr_new;
rfc2198_hdr *hdr_chain = NULL;
struct _rtp_conversation_info *p_conv_data= NULL;
gchar *payload_type_str;
/* Retrieve RTPs idea of a converation */
p_conv_data = (struct _rtp_conversation_info *)p_get_proto_data(pinfo->fd, proto_rtp, 0);
/* Add try to RFC 2198 data */
ti = proto_tree_add_text(tree, tvb, offset, -1, "RFC 2198: Redundant Audio Data");
rfc2198_tree = proto_item_add_subtree(ti, ett_rtp_rfc2198);
hdr_last = NULL;
cnt = 0;
while (hdr_follow) {
cnt++;
payload_type_str = NULL;
/* Allocate and fill in header */
hdr_new = wmem_new(wmem_packet_scope(), rfc2198_hdr);
hdr_new->next = NULL;
octet1 = tvb_get_guint8(tvb, offset);
hdr_new->pt = RTP_PAYLOAD_TYPE(octet1);
hdr_follow = (octet1 & 0x80);
/* 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_conv_data && p_conv_data->rtp_dyn_payload){
encoding_name_and_rate_t *encoding_name_and_rate_pt = NULL;
encoding_name_and_rate_pt = (encoding_name_and_rate_t *)g_hash_table_lookup(p_conv_data->rtp_dyn_payload, &hdr_new->pt);
if (encoding_name_and_rate_pt) {
payload_type_str = encoding_name_and_rate_pt->encoding_name;
}
}
}
/* Add a subtree for this header and add items */
ti = proto_tree_add_text(rfc2198_tree, tvb, offset, (hdr_follow)?4:1, "Header %u", cnt);
rfc2198_hdr_tree = proto_item_add_subtree(ti, ett_rtp_rfc2198_hdr);
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);
}
dissect_rtp_data(tvb, pinfo, tree, rfc2198_tree, hdr_last->offset, hdr_last->len, hdr_last->len, hdr_last->pt);
offset += hdr_last->len;
hdr_last = hdr_last->next;
}
}
static void
dissect_rtp_hext_rfc5215_onebyte( tvbuff_t *tvb, packet_info *pinfo,
proto_tree *rtp_hext_tree )
{
proto_item *ti = NULL;
proto_tree *rtp_hext_rfc5285_tree = NULL;
guint ext_offset = 0, start_ext_offset;
while (ext_offset < tvb_length (tvb)) {
guint8 ext_hdr_hdr;
guint8 ext_id;
guint8 ext_length;
tvbuff_t *subtvb = NULL;
/* 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_length (tvb))
return;
}
/* Add padding */
if (ext_offset > start_ext_offset)
proto_tree_add_item(rtp_hext_tree, hf_rtp_padding_data, tvb, 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;
if (rtp_hext_tree) {
ti = proto_tree_add_text(rtp_hext_tree, tvb, ext_offset, ext_length + 1, "RFC 5285 Header Extension (One-Byte Header)");
rtp_hext_rfc5285_tree = proto_item_add_subtree( ti, ett_hdr_ext_rfc5285);
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(tvb, ext_offset, ext_length, 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_rfc5215_twobytes(tvbuff_t *parent_tvb, guint id_offset,
guint8 id, tvbuff_t *tvb, packet_info *pinfo, proto_tree *rtp_hext_tree)
{
proto_item *ti = NULL;
proto_tree *rtp_hext_rfc5285_tree = NULL;
guint ext_offset = 0, start_ext_offset;
while (ext_offset + 2 < tvb_length (tvb)) {
guint8 ext_id;
guint8 ext_length;
tvbuff_t *subtvb = NULL;
/* 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_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, 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) {
ti = proto_tree_add_text(rtp_hext_tree, tvb, ext_offset, ext_length + 2, "RFC 5285 Header Extension (Two-Byte Header)");
rtp_hext_rfc5285_tree = proto_item_add_subtree( ti, ett_hdr_ext_rfc5285);
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(tvb, ext_offset, ext_length, 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;
proto_tree *rtp_csrc_tree = NULL;
proto_tree *rtp_hext_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;
gchar *payload_type_str = NULL;
gboolean is_srtp = FALSE;
unsigned int i = 0;
unsigned int hdr_extension_len= 0;
unsigned int hdr_extension_id = 0;
volatile unsigned int padding_count;
gint length, reported_length;
int data_len;
volatile unsigned int offset = 0;
guint16 seq_num;
guint32 timestamp;
guint32 sync_src;
guint32 csrc_item;
struct _rtp_conversation_info *p_conv_data = NULL;
/*struct srtp_info *srtp_info = NULL;*/
/*unsigned int srtp_offset;*/
unsigned int hdrext_offset = 0;
tvbuff_t *newtvb = NULL;
const char *pt = NULL;
/* Can tap up to 4 RTP packets within same packet */
static struct _rtp_info rtp_info_arr[4];
static int rtp_info_current=0;
struct _rtp_info *rtp_info;
rtp_info_current++;
if (rtp_info_current==4) {
rtp_info_current=0;
}
rtp_info = &rtp_info_arr[rtp_info_current];
/* Get the fields in the first octet */
octet1 = tvb_get_guint8( tvb, offset );
version = RTP_VERSION( octet1 );
if (version == 0) {
switch (global_rtp_version0_type) {
case RTP0_STUN:
call_dissector(stun_handle, tvb, pinfo, tree);
return tvb_length(tvb);
case RTP0_CLASSICSTUN:
call_dissector(classicstun_handle, tvb, pinfo, tree);
return tvb_length(tvb);
case RTP0_T38:
call_dissector(t38_handle, tvb, pinfo, tree);
return tvb_length(tvb);
case RTP0_SPRT:
call_dissector(sprt_handle, tvb, pinfo, tree);
return tvb_length(tvb);
case RTP0_INVALID:
if (!(tvb_memeql(tvb, 4, "ZRTP", 4)))
{
call_dissector(zrtp_handle,tvb,pinfo,tree);
return tvb_length(tvb);
}
default:
; /* Unknown or unsupported version (let it fall through) */
}
}
/* fill in the rtp_info structure */
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);
}
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 */
rtp_info->info_padding_set = padding_set;
rtp_info->info_padding_count = 0;
rtp_info->info_marker_set = marker_set;
rtp_info->info_is_video = FALSE;
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_is_srtp = FALSE;
rtp_info->info_setup_frame_num = 0;
rtp_info->info_payload_type_str = NULL;
rtp_info->info_payload_rate = 0;
/*
* Do we have all the data?
*/
length = tvb_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 */
get_conv_info(pinfo, rtp_info);
p_conv_data = (struct _rtp_conversation_info *)p_get_proto_data(pinfo->fd, proto_rtp, 0);
if (p_conv_data)
rtp_info->info_is_video = p_conv_data->is_video;
if (p_conv_data && p_conv_data->srtp_info) is_srtp = TRUE;
rtp_info->info_is_srtp = is_srtp;
col_set_str( pinfo->cinfo, COL_PROTOCOL, (is_srtp) ? "SRTP" : "RTP" );
/* check if this is added as an SRTP stream - if so, don't try to dissect the payload data for now */
p_conv_data = (struct _rtp_conversation_info *)p_get_proto_data(pinfo->fd, proto_rtp, 0);
#if 0 /* XXX: srtp_offset never actually used ?? */
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_conv_data && p_conv_data->bta2dp_info && p_conv_data->bta2dp_info->codec_dissector) {
rtp_info->info_payload_type_str = (const char *) dissector_handle_get_short_name(p_conv_data->bta2dp_info->codec_dissector);
} else if (p_conv_data && p_conv_data->btvdp_info && p_conv_data->btvdp_info->codec_dissector) {
rtp_info->info_payload_type_str = (const char *) dissector_handle_get_short_name(p_conv_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_conv_data && p_conv_data->rtp_dyn_payload){
encoding_name_and_rate_t *encoding_name_and_rate_pt = NULL;
encoding_name_and_rate_pt = (encoding_name_and_rate_t *)g_hash_table_lookup(p_conv_data->rtp_dyn_payload, &payload_type);
if (encoding_name_and_rate_pt) {
rtp_info->info_payload_type_str = payload_type_str = encoding_name_and_rate_pt->encoding_name;
rtp_info->info_payload_rate = encoding_name_and_rate_pt->sample_rate;
}
}
}
if (p_conv_data && p_conv_data->bta2dp_info) {
pt = (p_conv_data->bta2dp_info->codec_dissector) ? dissector_handle_get_short_name(p_conv_data->bta2dp_info->codec_dissector) : "Unknown";
} else if (p_conv_data && p_conv_data->btvdp_info) {
pt = (p_conv_data->btvdp_info->codec_dissector) ? dissector_handle_get_short_name(p_conv_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_uint( rtp_tree, hf_rtp_version, tvb,
offset, 1, octet1 );
proto_tree_add_boolean( rtp_tree, hf_rtp_padding, tvb,
offset, 1, octet1 );
proto_tree_add_boolean( rtp_tree, hf_rtp_extension, tvb,
offset, 1, octet1 );
proto_tree_add_uint( rtp_tree, hf_rtp_csrc_count, tvb,
offset, 1, octet1 );
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_conv_data != NULL) {
item = proto_tree_add_uint( rtp_tree, hf_rtp_ext_seq_nr, tvb, offset, 2, p_conv_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 ) {
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 ) {
/* Defined by profile field is 16 bits (2 octets) */
hdr_extension_id = tvb_get_ntohs( tvb, offset );
if ( tree ) 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 );
if ( tree ) proto_tree_add_uint( rtp_tree, hf_rtp_length, tvb, offset, 2, hdr_extension_len);
offset += 2;
if ( hdr_extension_len > 0 ) {
if ( tree ) {
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(tvb, offset, hdr_extension_len * 4, hdr_extension_len * 4);
if (hdr_extension_id == RTP_RFC5215_ONE_BYTE_SIG) {
dissect_rtp_hext_rfc5215_onebyte (newtvb, pinfo, rtp_hext_tree);
}
else if ((hdr_extension_id & RTP_RFC5215_TWO_BYTE_MASK) == RTP_RFC5215_TWO_BYTE_SIG) {
dissect_rtp_hext_rfc5215_twobytes(tvb,
offset - 4, hdr_extension_id, newtvb,
pinfo, rtp_hext_tree);
}
else {
if ( !(dissector_try_uint(rtp_hdr_ext_dissector_table, hdr_extension_id, newtvb, pinfo, rtp_hext_tree)) ) {
hdrext_offset = offset;
for ( i = 0; i < hdr_extension_len; i++ ) {
if ( tree ) proto_tree_add_uint( rtp_hext_tree, hf_rtp_hdr_ext, tvb, hdrext_offset, 4, tvb_get_ntohl( tvb, hdrext_offset ) );
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.
*/
if (tvb_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.
*/
if ( tree ) proto_tree_add_text(rtp_tree, tvb, 0, 0,
"Frame has padding, but not all the frame data was captured");
call_dissector(data_handle,
tvb_new_subset_remaining(tvb, offset),
pinfo, rtp_tree);
return tvb_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;
rtp_info->info_payload_len = tvb_length_remaining(tvb, offset);
rtp_info->info_padding_count = padding_count;
if (p_conv_data && p_conv_data->bta2dp_info) {
if (p_conv_data->bta2dp_info->codec_dissector == sbc_handle) {
rtp_info->info_payload_offset += 1;
rtp_info->info_payload_len -= 1;
}
if (p_conv_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_conv_data && p_conv_data->btvdp_info &&
p_conv_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 (data_len > 0) {
/*
* There's data left over when you take out
* the padding; dissect it.
*/
/* 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);
} 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.
*/
if ( tree ) 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.
*/
if ( tree ) 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_length_remaining(tvb, offset);
if (p_conv_data && p_conv_data->bta2dp_info) {
if (p_conv_data->bta2dp_info->codec_dissector == sbc_handle) {
rtp_info->info_payload_offset += 1;
rtp_info->info_payload_len -= 1;
}
if (p_conv_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_conv_data && p_conv_data->btvdp_info &&
p_conv_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 (tvb_reported_length_remaining(tvb, offset) > 0) {
/* Ensure that tap is called after packet dissection, even in case of exception */
TRY {
dissect_rtp_data( tvb, pinfo, tree, rtp_tree, offset,
tvb_length_remaining( tvb, offset ),
tvb_reported_length_remaining( tvb, offset ),
payload_type);
} 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;
}
static void
dissect_rtp_hdr_ext_ed137(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
{
unsigned int offset = 0;
unsigned int hdr_extension_len = 0;
proto_item *ti = NULL;
proto_item *ti2 = NULL;
proto_tree *rtp_hext_tree = NULL;
proto_tree *rtp_hext_tree2 = NULL;
unsigned int i;
guint32 ext_value;
unsigned int ft_type = 0;
unsigned int bss_qidx = 0;
unsigned int bss_qidx_ml = 0;
hdr_extension_len = tvb_reported_length(tvb)/4;
if ( hdr_extension_len > 0 ) {
unsigned int hdrext_offset = 0;
if ( tree ) {
ti = proto_tree_add_item(tree, hf_rtp_hdr_ed137s, tvb, offset, hdr_extension_len * 4, ENC_NA);
rtp_hext_tree = proto_item_add_subtree( ti, ett_hdr_ext_ed137s );
}
for(i=0; i<hdr_extension_len; i++) {
if ( tree ) {
ti2 = proto_tree_add_item(rtp_hext_tree, hf_rtp_hdr_ed137, tvb, hdrext_offset, 4, ENC_NA);
rtp_hext_tree2 = proto_item_add_subtree( ti2, ett_hdr_ext_ed137 );
ext_value=tvb_get_ntohl( tvb, hdrext_offset );
if (RTP_ED137_ptt_mask(ext_value)) {
col_append_str(pinfo->cinfo, COL_INFO, ", PTT");
}
if (RTP_ED137_squ_mask(ext_value)) {
col_append_str(pinfo->cinfo, COL_INFO, ", SQU");
}
/* Following bits are used from ED137 RTPRx/RTPTx Information field */
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137_ptt_type, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137_squ, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137_ptt_id, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137_sct, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137_x, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
if (RTP_ED137_extended_information(ext_value)) {
/* Extended information is used */
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137_ft_type, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137_ft_len, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
ft_type=RTP_ED137_feature_type(ext_value);
switch (ft_type) {
case RTP_ED137_feature_bss_type:
bss_qidx=RTP_ED137_feature_bss_qidx(ext_value);
bss_qidx_ml=RTP_ED137_feature_bss_qidx_ml(ext_value);
if (0==bss_qidx_ml) {
/* Special handling for RSSI method */
if (bss_qidx<=15) {
/* Correct range */
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137_ft_bss_rssi_qidx, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
}
else {
/* Handle as other method */
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137_ft_bss_qidx, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
}
}
else {
/* Other BSS method handling */
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137_ft_bss_qidx, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
}
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137_ft_bss_qidx_ml, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137_ft_bss_nu, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
break;
default:
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137_ft_value, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
break;
}
}
else {
/* Extended information is not used */
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137_x_nu, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
}
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137_vf, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
}
hdrext_offset += 4;
}
}
}
static void
dissect_rtp_hdr_ext_ed137a(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
{
unsigned int offset = 0;
unsigned int hdr_extension_len = 0;
proto_item *ti = NULL;
proto_item *ti2 = NULL;
proto_tree *rtp_hext_tree = NULL;
proto_tree *rtp_hext_tree2 = NULL;
unsigned int i;
guint32 ext_value;
unsigned int ft_type = 0;
hdr_extension_len = tvb_reported_length(tvb)/4;
if ( hdr_extension_len > 0 ) {
unsigned int hdrext_offset = 0;
if ( tree ) {
ti = proto_tree_add_item(tree, hf_rtp_hdr_ed137s, tvb, offset, hdr_extension_len * 4, ENC_NA);
rtp_hext_tree = proto_item_add_subtree( ti, ett_hdr_ext_ed137s );
}
for(i=0; i<hdr_extension_len; i++) {
if ( tree ) {
ti2 = proto_tree_add_item(rtp_hext_tree, hf_rtp_hdr_ed137a, tvb, hdrext_offset, 4, ENC_NA);
rtp_hext_tree2 = proto_item_add_subtree( ti2, ett_hdr_ext_ed137a );
ext_value=tvb_get_ntohl( tvb, hdrext_offset );
if (RTP_ED137A_ptt_mask(ext_value)) {
col_append_str(pinfo->cinfo, COL_INFO, ", PTT");
}
if (RTP_ED137A_squ_mask(ext_value)) {
col_append_str(pinfo->cinfo, COL_INFO, ", SQU");
}
/* Following bits are used from ED137A/B RTPRx Information field */
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137a_ptt_type, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137a_squ, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137a_ptt_id, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137a_pm, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137a_ptts, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137a_sct, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137a_reserved, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137a_x, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
if (RTP_ED137A_extended_information(ext_value)) {
/* Extended information is used */
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137a_ft_type, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137a_ft_len, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
ft_type=RTP_ED137A_feature_type(ext_value);
switch (ft_type) {
default:
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137a_ft_value, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
break;
}
}
else {
/* Extended information is not used */
proto_tree_add_item( rtp_hext_tree2, hf_rtp_hdr_ed137a_x_nu, tvb, hdrext_offset, 4, ENC_BIG_ENDIAN);
}
}
hdrext_offset += 4;
}
}
}
/* 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;
}
/* Look for conversation info */
static void
get_conv_info(packet_info *pinfo, struct _rtp_info *rtp_info)
{
/* Conversation and current data */
conversation_t *p_conv = NULL;
struct _rtp_conversation_info *p_conv_data = NULL;
/* Use existing packet info if available */
p_conv_data = (struct _rtp_conversation_info *)p_get_proto_data(pinfo->fd, proto_rtp, 0);
if (!p_conv_data)
{
/* First time, get info from conversation */
p_conv = find_conversation(pinfo->fd->num, &pinfo->net_dst, &pinfo->net_src,
pinfo->ptype,
pinfo->destport, pinfo->srcport, NO_ADDR_B);
if (p_conv)
{
/* Create space for packet info */
struct _rtp_conversation_info *p_conv_packet_data;
p_conv_data = (struct _rtp_conversation_info *)conversation_get_proto_data(p_conv, proto_rtp);
if (p_conv_data) {
guint32 seqno;
/* Save this conversation info into packet info */
p_conv_packet_data = wmem_new(wmem_file_scope(), struct _rtp_conversation_info);
g_strlcpy(p_conv_packet_data->method, p_conv_data->method, MAX_RTP_SETUP_METHOD_SIZE+1);
p_conv_packet_data->frame_number = p_conv_data->frame_number;
p_conv_packet_data->is_video = p_conv_data->is_video;
p_conv_packet_data->rtp_dyn_payload = p_conv_data->rtp_dyn_payload;
p_conv_packet_data->rtp_conv_info = p_conv_data->rtp_conv_info;
p_conv_packet_data->srtp_info = p_conv_data->srtp_info;
p_conv_packet_data->bta2dp_info = p_conv_data->bta2dp_info;
p_conv_packet_data->btvdp_info = p_conv_data->btvdp_info;
p_add_proto_data(pinfo->fd, proto_rtp, 0, p_conv_packet_data);
/* calculate extended sequence number */
seqno = calculate_extended_seqno(p_conv_data->extended_seqno,
rtp_info->info_seq_num);
p_conv_packet_data->extended_seqno = seqno;
p_conv_data->extended_seqno = seqno;
}
}
}
if (p_conv_data) rtp_info->info_setup_frame_num = p_conv_data->frame_number;
}
/* Display setup info */
static void
show_setup_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
/* Conversation and current data */
struct _rtp_conversation_info *p_conv_data = NULL;
proto_tree *rtp_setup_tree;
proto_item *ti;
/* Use existing packet info if available */
p_conv_data = (struct _rtp_conversation_info *)p_get_proto_data(pinfo->fd, proto_rtp, 0);
if (!p_conv_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_conv_data->method,
p_conv_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_conv_data->frame_number);
PROTO_ITEM_SET_GENERATED(item);
item = proto_tree_add_string(rtp_setup_tree, hf_rtp_setup_method,
tvb, 0, 0, p_conv_data->method);
PROTO_ITEM_SET_GENERATED(item);
}
}
/* Dissect PacketCable CCC header */
static int
dissect_pkt_ccc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
{
proto_item *ti = NULL;
proto_tree *pkt_ccc_tree = NULL;
if ( 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,
};
module_t *pkt_ccc_module;
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));
new_register_dissector("pkt_ccc", dissect_pkt_ccc, proto_pkt_ccc);
pkt_ccc_module = prefs_register_protocol(proto_pkt_ccc, proto_reg_handoff_pkt_ccc);
prefs_register_uint_preference(pkt_ccc_module, "udp_port",
"UDP port",
"Decode packets on this UDP port as PacketCable CCC",
10, &global_pkt_ccc_udp_port);
}
void
proto_reg_handoff_pkt_ccc(void)
{
/*
* Register this dissector as one that can be selected by a
* UDP port number.
*/
static gboolean initialized = FALSE;
static dissector_handle_t pkt_ccc_handle;
static guint saved_pkt_ccc_udp_port;
if (!initialized) {
pkt_ccc_handle = find_dissector("pkt_ccc");
dissector_add_handle("udp.port", pkt_ccc_handle); /* for 'decode-as' */
initialized = TRUE;
} else {
if (saved_pkt_ccc_udp_port != 0) {
dissector_delete_uint("udp.port", saved_pkt_ccc_udp_port, pkt_ccc_handle);
}
}
if (global_pkt_ccc_udp_port != 0) {
dissector_add_uint("udp.port", global_pkt_ccc_udp_port, pkt_ccc_handle);
}
saved_pkt_ccc_udp_port = global_pkt_ccc_udp_port;
}
/* 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,
VALS(rtp_ext_profile_vals),
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
}
},
/* ED137 and ED137A common structures */
{
&hf_rtp_hdr_ed137s,
{
"ED137 extensions",
"rtp.ext.ed137s",
FT_NONE,
BASE_NONE,
NULL,
0x0,
NULL, HFILL
}
},
/* ED137 only structures */
{
&hf_rtp_hdr_ed137,
{
"ED137 extension",
"rtp.ext.ed137",
FT_NONE,
BASE_NONE,
NULL,
0x0,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137_ptt_type,
{
"PTT Type",
"rtp.ext.ed137.ptt_type",
FT_UINT32,
BASE_DEC,
VALS(rtp_ext_ed137_ptt_type),
0xE0000000,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137_squ,
{
"SQU",
"rtp.ext.ed137.squ",
FT_UINT32,
BASE_DEC,
VALS(rtp_ext_ed137_squ),
0x10000000,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137_ptt_id,
{
"PTT-id",
"rtp.ext.ed137.ptt_id",
FT_UINT32,
BASE_DEC,
NULL,
0x0F000000,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137_sct,
{
"Simultaneous Call Transmissions",
"rtp.ext.ed137.sct",
FT_UINT32,
BASE_DEC,
NULL,
0x00800000,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137_x,
{
"X",
"rtp.ext.ed137.x",
FT_UINT32,
BASE_DEC,
NULL,
0x00400000,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137_x_nu,
{
"Not used",
"rtp.ext.ed137.x-nu",
FT_UINT32,
BASE_DEC,
NULL,
0x003FFFFE,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137_ft_type,
{
"Feature type",
"rtp.ext.ed137.ft.type",
FT_UINT32,
BASE_HEX_DEC,
VALS(rtp_ext_ed137_ft_type),
0x003C0000,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137_ft_len,
{
"Feature length",
"rtp.ext.ed137.ft.len",
FT_UINT32,
BASE_DEC,
NULL,
0x0003C000,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137_ft_value,
{
"Feature value",
"rtp.ext.ed137.ft.value",
FT_UINT32,
BASE_HEX_DEC,
NULL,
0x00003FFE,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137_vf,
{
"VF",
"rtp.ext.ed137.vf",
FT_UINT32,
BASE_DEC,
VALS(rtp_ext_ed137_vf),
0x00000001,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137_ft_bss_qidx,
{
"BSS Quality Index",
"rtp.ext.ed137.ft.bss.qidx",
FT_UINT32,
BASE_DEC,
NULL,
0x00003FC0,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137_ft_bss_rssi_qidx,
{
"BSS Quality Index",
"rtp.ext.ed137.ft.bss.qidx",
FT_UINT32,
BASE_DEC,
VALS(rtp_ext_ed137_ft_bss_rssi_qidx),
0x00003FC0,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137_ft_bss_qidx_ml,
{
"BSS Quality Index Method",
"rtp.ext.ed137.ft.bss.qidx-ml",
FT_UINT32,
BASE_DEC,
VALS(rtp_ext_ed137_ft_bss_qidx_ml),
0x00000038,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137_ft_bss_nu,
{
"Not used",
"rtp.ext.ed137.ft.bss-nu",
FT_UINT32,
BASE_DEC,
NULL,
0x00000006,
NULL, HFILL
}
},
/* ED137A only structures */
{
&hf_rtp_hdr_ed137a,
{
"ED137A extension",
"rtp.ext.ed137A",
FT_NONE,
BASE_NONE,
NULL,
0x0,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137a_ptt_type,
{
"PTT Type",
"rtp.ext.ed137A.ptt_type",
FT_UINT32,
BASE_DEC,
VALS(rtp_ext_ed137a_ptt_type),
0xE0000000,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137a_squ,
{
"SQU",
"rtp.ext.ed137A.squ",
FT_UINT32,
BASE_DEC,
VALS(rtp_ext_ed137a_squ),
0x10000000,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137a_ptt_id,
{
"PTT-id",
"rtp.ext.ed137A.ptt_id",
FT_UINT32,
BASE_DEC,
NULL,
0x0FC00000,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137a_pm,
{
"PTT Mute",
"rtp.ext.ed137A.pm",
FT_UINT32,
BASE_DEC,
NULL,
0x00200000,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137a_ptts,
{
"PTT Summation",
"rtp.ext.ed137A.ptts",
FT_UINT32,
BASE_DEC,
NULL,
0x00100000,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137a_sct,
{
"Simultaneous Call Transmissions",
"rtp.ext.ed137a.sct",
FT_UINT32,
BASE_DEC,
NULL,
0x00080000,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137a_reserved,
{
"Reserved",
"rtp.ext.ed137A.reserved",
FT_UINT32,
BASE_HEX_DEC,
NULL,
0x00060000,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137a_x,
{
"X",
"rtp.ext.ed137A.x",
FT_UINT32,
BASE_DEC,
NULL,
0x00010000,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137a_x_nu,
{
"Not used",
"rtp.ext.ed137A.x-nu",
FT_UINT32,
BASE_DEC,
NULL,
0x0000FFFF,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137a_ft_type,
{
"Feature type",
"rtp.ext.ed137A.ft.type",
FT_UINT32,
BASE_HEX_DEC,
VALS(rtp_ext_ed137a_ft_type),
0x0000F000,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137a_ft_len,
{
"Feature length",
"rtp.ext.ed137A.ft.len",
FT_UINT32,
BASE_DEC,
NULL,
0x00000F00,
NULL, HFILL
}
},
{
&hf_rtp_hdr_ed137a_ft_value,
{
"Feature value",
"rtp.ext.ed137A.ft.value",
FT_UINT32,
BASE_HEX_DEC,
NULL,
0x000000FF,
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
}
},
/* 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 }
},
{&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_hdr_ext_ed137s,
&ett_hdr_ext_ed137,
&ett_hdr_ext_ed137a,
&ett_rtp_setup,
&ett_rtp_rfc2198,
&ett_rtp_rfc2198_hdr,
&ett_rtp_fragment,
&ett_rtp_fragments
};
module_t *rtp_module;
proto_rtp = proto_register_protocol("Real-Time Transport Protocol",
"RTP", "rtp");
proto_register_field_array(proto_rtp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
new_register_dissector("rtp", dissect_rtp, proto_rtp);
register_dissector("rtp.rfc2198", dissect_rtp_rfc2198, proto_rtp);
rtp_tap = register_tap("rtp");
rtp_pt_dissector_table = register_dissector_table("rtp.pt",
"RTP payload type", FT_UINT8, BASE_DEC);
rtp_dyn_pt_dissector_table = register_dissector_table("rtp_dyn_payload_type",
"Dynamic RTP payload type", FT_STRING, BASE_NONE);
rtp_hdr_ext_dissector_table = register_dissector_table("rtp.hdr_ext",
"RTP header extension", FT_UINT32, BASE_HEX);
rtp_hdr_ext_rfc5285_dissector_table = register_dissector_table("rtp.ext.rfc5285.id",
"RTP Generic header extension (RFC 5285)", FT_UINT8, BASE_DEC);
register_dissector("rtp.ext.ed137", dissect_rtp_hdr_ext_ed137, proto_rtp);
register_dissector("rtp.ext.ed137a", dissect_rtp_hdr_ext_ed137a, proto_rtp);
rtp_module = prefs_register_protocol(proto_rtp, proto_reg_handoff_rtp);
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_bool_preference(rtp_module, "heuristic_rtp",
"Try to decode RTP outside of conversations",
"If call control SIP/H323/RTSP/.. messages are missing in the trace, "
"RTP isn't decoded without this",
&global_rtp_heur);
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_uint_preference(rtp_module,
"rfc2198_payload_type", "Payload Type for RFC2198",
"Payload Type for RFC2198 Redundant Audio Data",
10,
&rtp_rfc2198_pt);
register_init_routine(rtp_fragment_init);
}
void
proto_reg_handoff_rtp(void)
{
static gboolean rtp_prefs_initialized = FALSE;
static dissector_handle_t rtp_rfc2198_handle;
static dissector_handle_t rtp_hdr_ext_ed137_handle;
static dissector_handle_t rtp_hdr_ext_ed137a_handle;
static guint rtp_saved_rfc2198_pt;
if (!rtp_prefs_initialized) {
rtp_handle = find_dissector("rtp");
rtp_rfc2198_handle = find_dissector("rtp.rfc2198");
dissector_add_handle("udp.port", rtp_handle); /* for 'decode-as' */
dissector_add_string("rtp_dyn_payload_type", "red", rtp_rfc2198_handle);
heur_dissector_add( "udp", dissect_rtp_heur_udp, proto_rtp);
heur_dissector_add("stun", dissect_rtp_heur_stun, proto_rtp);
rtp_hdr_ext_ed137_handle = find_dissector("rtp.ext.ed137");
rtp_hdr_ext_ed137a_handle = find_dissector("rtp.ext.ed137a");
dissector_add_uint("rtp.hdr_ext", RTP_ED137_SIG, rtp_hdr_ext_ed137_handle);
dissector_add_uint("rtp.hdr_ext", RTP_ED137A_SIG, rtp_hdr_ext_ed137a_handle);
data_handle = find_dissector("data");
stun_handle = find_dissector("stun-udp");
classicstun_handle = find_dissector("classicstun");
classicstun_heur_handle = find_dissector("classicstun-heur");
stun_heur_handle = find_dissector("stun-heur");
t38_handle = find_dissector("t38");
zrtp_handle = find_dissector("zrtp");
sprt_handle = find_dissector("sprt");
v150fw_handle = find_dissector("v150fw");
bta2dp_content_protection_header_scms_t = find_dissector("bta2dp_content_protection_header_scms_t");
btvdp_content_protection_header_scms_t = find_dissector("btvdp_content_protection_header_scms_t");
bta2dp_handle = find_dissector("bta2dp");
btvdp_handle = find_dissector("btvdp");
sbc_handle = find_dissector("sbc");
dissector_add_string("rtp_dyn_payload_type", "v150fw", v150fw_handle);
dissector_add_handle("btl2cap.cid", rtp_handle);
rtp_prefs_initialized = TRUE;
} else {
dissector_delete_uint("rtp.pt", rtp_saved_rfc2198_pt, rtp_rfc2198_handle);
}
dissector_add_uint("rtp.pt", rtp_rfc2198_pt, rtp_rfc2198_handle);
rtp_saved_rfc2198_pt = rtp_rfc2198_pt;
}
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 8
* tab-width: 8
* indent-tabs-mode: t
* End:
*
* vi: set shiftwidth=8 tabstop=8 noexpandtab:
* :indentSize=8:tabSize=8:noTabs=false:
*/