/* packet-rtcp.c * * Routines for RTCP dissection * RTCP = Real-time Transport Control Protocol * * Copyright 2000, Philips Electronics N.V. * Written by Andreas Sikkema * * Copyright 2004, Anders Broman * * Copyright 2005, Nagarjuna Venna * * Copyright 2010, Matteo Valdina * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later */ /* * This dissector tries to dissect the RTCP protocol according to Annex A * of ITU-T Recommendation H.225.0 (02/98) and RFC 3550 (obsoleting 1889). * H.225.0 literally copies RFC 1889, but omitting a few sections. * * RTCP traffic is traditionally handled by an uneven UDP portnumber. This * can be any port number, but there is a registered port available, port 5005 * 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. * * Information on PoC can be found from * https://www.omaspecworks.org (OMA SpecWorks, formerly the Open * Mobile Alliance - http://www.openmobilealliance.org/) * * RTCP XR is specified in RFC 3611. * * See also https://www.iana.org/assignments/rtp-parameters * * RTCP FB is specified in RFC 4585 and extended by RFC 5104 * * MS-RTP: Real-time Transport Protocol (RTP) Extensions * https://docs.microsoft.com/en-us/openspecs/office_protocols/ms-rtp */ /* * The part of this dissector for IDMS XR blocks was written by * Torsten Loebner (loebnert@googlemail.com) in the context of a graduation * project with the research organization TNO in Delft, Netherland. * The extension is based on the RTCP XR block specified in * ETSI TS 182 063 v3.5.2 Annex W (https://www.etsi.org/deliver/etsi_ts/183000_183099/183063/), * which was registered by IANA as RTCP XR Block Type 12 * (https://www.iana.org/assignments/rtcp-xr-block-types/rtcp-xr-block-types.xml). */ #include "config.h" #include #include #include "packet-rtcp.h" #include "packet-rtp.h" #include "packet-gsm_a_common.h" #include #include #include #include #include void proto_register_rtcp(void); void proto_reg_handoff_rtcp(void); /* Version is the first 2 bits of the first octet*/ #define RTCP_VERSION(octet) ((octet) >> 6) /* Padding is the third bit; no need to shift, because true is any value other than 0! */ #define RTCP_PADDING(octet) ((octet) & 0x20) /* Receiver/ Sender count is the 5 last bits */ #define RTCP_COUNT(octet) ((octet) & 0x1F) static dissector_handle_t rtcp_handle; static dissector_handle_t srtcp_handle; /* add dissector table to permit sub-protocol registration */ static dissector_table_t rtcp_dissector_table; static dissector_table_t rtcp_psfb_dissector_table; static dissector_table_t rtcp_rtpfb_dissector_table; static const value_string rtcp_version_vals[] = { { 2, "RFC 1889 Version" }, { 0, "Old VAT Version" }, { 1, "First Draft Version" }, { 0, NULL }, }; #define RTCP_PT_MIN 192 /* Supplemental H.261 specific RTCP packet types according to Section C.3.5 */ #define RTCP_FIR 192 #define RTCP_NACK 193 #define RTCP_SMPTETC 194 #define RTCP_IJ 195 /* RTCP packet types according to Section A.11.1 */ /* And https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml */ #define RTCP_SR 200 #define RTCP_RR 201 #define RTCP_SDES 202 #define RTCP_BYE 203 #define RTCP_APP 204 #define RTCP_RTPFB 205 #define RTCP_PSFB 206 #define RTCP_XR 207 #define RTCP_AVB 208 #define RTCP_RSI 209 #define RTCP_TOKEN 210 #define RTCP_PT_MAX 210 static const value_string rtcp_packet_type_vals[] = { { RTCP_SR, "Sender Report" }, { RTCP_RR, "Receiver Report" }, { RTCP_SDES, "Source description" }, { RTCP_BYE, "Goodbye" }, { RTCP_APP, "Application specific" }, { RTCP_RTPFB, "Generic RTP Feedback" }, { RTCP_PSFB, "Payload-specific Feedback" }, { RTCP_XR, "Extended report (RFC 3611)"}, { RTCP_AVB, "AVB RTCP packet (IEEE1733)" }, { RTCP_RSI, "Receiver Summary Information" }, { RTCP_TOKEN, "Port Mapping" }, { RTCP_FIR, "Full Intra-frame Request (H.261)" }, { RTCP_NACK, "Negative Acknowledgement (H.261)" }, { RTCP_SMPTETC, "SMPTE time-code mapping" }, { RTCP_IJ, "Extended inter-arrival jitter report" }, { 0, NULL } }; /* RTCP SDES types (Section A.11.2) */ #define RTCP_SDES_END 0 #define RTCP_SDES_CNAME 1 #define RTCP_SDES_NAME 2 #define RTCP_SDES_EMAIL 3 #define RTCP_SDES_PHONE 4 #define RTCP_SDES_LOC 5 #define RTCP_SDES_TOOL 6 #define RTCP_SDES_NOTE 7 #define RTCP_SDES_PRIV 8 #define RTCP_SDES_H323_CADDR 9 #define RTCP_SDES_APSI 10 static const value_string rtcp_sdes_type_vals[] = { { RTCP_SDES_END, "END" }, { RTCP_SDES_CNAME, "CNAME (user and domain)" }, { RTCP_SDES_NAME, "NAME (common name)" }, { RTCP_SDES_EMAIL, "EMAIL (e-mail address)" }, { RTCP_SDES_PHONE, "PHONE (phone number)" }, { RTCP_SDES_LOC, "LOC (geographic location)" }, { RTCP_SDES_TOOL, "TOOL (name/version of source app)" }, { RTCP_SDES_NOTE, "NOTE (note about source)" }, { RTCP_SDES_PRIV, "PRIV (private extensions)" }, { RTCP_SDES_H323_CADDR, "H323-CADDR (H.323 callable address)" }, { RTCP_SDES_APSI, "Application Specific Identifier" }, { 0, NULL } }; /* RTCP XR Blocks (Section 4, RTC 3611) * or https://www.iana.org/assignments/rtcp-xr-block-types */ #define RTCP_XR_LOSS_RLE 1 #define RTCP_XR_DUP_RLE 2 #define RTCP_XR_PKT_RXTIMES 3 #define RTCP_XR_REF_TIME 4 #define RTCP_XR_DLRR 5 #define RTCP_XR_STATS_SUMRY 6 #define RTCP_XR_VOIP_METRCS 7 #define RTCP_XR_BT_XNQ 8 #define RTCP_XR_TI_VOIP 9 #define RTCP_XR_PR_LOSS_RLE 10 #define RTCP_XR_MC_ACQ 11 #define RTCP_XR_IDMS 12 static const value_string rtcp_xr_type_vals[] = { { RTCP_XR_LOSS_RLE, "Loss Run Length Encoding Report Block" }, { RTCP_XR_DUP_RLE, "Duplicate Run Length Encoding Report Block" }, { RTCP_XR_PKT_RXTIMES, "Packet Receipt Times Report Block" }, { RTCP_XR_REF_TIME, "Receiver Reference Time Report Block" }, { RTCP_XR_DLRR, "DLRR Report Block" }, { RTCP_XR_STATS_SUMRY, "Statistics Summary Report Block" }, { RTCP_XR_VOIP_METRCS, "VoIP Metrics Report Block" }, { RTCP_XR_BT_XNQ, "BT XNQ RTCP XR (RFC5093) Report Block" }, { RTCP_XR_TI_VOIP, "Texas Instruments Extended VoIP Quality Block" }, { RTCP_XR_PR_LOSS_RLE, "Post-repair Loss RLE Report Block" }, { RTCP_XR_MC_ACQ, "Multicast Acquisition Report Block" }, { RTCP_XR_IDMS, "Inter-destination Media Synchronization Block" }, /* [https://www.etsi.org/deliver/etsi_ts/183000_183099/183063/][ETSI 183 063][Miguel_Angel_Reina_Ortega] */ { 0, NULL} }; /* XR VoIP Metrics Block - PLC Algorithms */ static const value_string rtcp_xr_plc_algo_vals[] = { { 0, "Unspecified" }, { 1, "Disabled" }, { 2, "Enhanced" }, { 3, "Standard" }, { 0, NULL } }; /* XR VoIP Metrics Block - JB Adaptive */ static const value_string rtcp_xr_jb_adaptive_vals[] = { { 0, "Unknown" }, { 1, "Reserved" }, { 2, "Non-Adaptive" }, { 3, "Adaptive" }, { 0, NULL } }; /* XR Stats Summary Block - IP TTL or Hop Limit */ static const value_string rtcp_xr_ip_ttl_vals[] = { { 0, "No TTL Values" }, { 1, "IPv4" }, { 2, "IPv6" }, { 3, "Undefined" }, { 0, NULL } }; /* XR IDMS synchronization packet sender type */ static const value_string rtcp_xr_idms_spst[] = { { 0, "Reserved" }, { 1, "SC" }, { 2, "MSAS" }, { 3, "SC' INPUT" }, { 4, "SC' OUTPUT" }, { 5, "Reserved" }, { 6, "Reserved" }, { 7, "Reserved" }, { 8, "Reserved" }, { 9, "Reserved" }, { 10, "Reserved" }, { 11, "Reserved" }, { 12, "Reserved" }, { 13, "Reserved" }, { 14, "Reserved" }, { 15, "Reserved" }, { 0, NULL } }; /* RTCP Application PoC1 Value strings * OMA-TS-PoC-UserPlane-V1_0-20060609-A */ #define TBCP_BURST_REQUEST 0 #define TBCP_BURST_GRANTED 1 #define TBCP_BURST_TAKEN_EXPECT_NO_REPLY 2 #define TBCP_BURST_DENY 3 #define TBCP_BURST_RELEASE 4 #define TBCP_BURST_IDLE 5 #define TBCP_BURST_REVOKE 6 #define TBCP_BURST_ACKNOWLEDGMENT 7 #define TBCP_QUEUE_STATUS_REQUEST 8 #define TBCP_QUEUE_STATUS_RESPONSE 9 #define TBCP_DISCONNECT 11 #define TBCP_CONNECT 15 #define TBCP_BURST_TAKEN_EXPECT_REPLY 18 static const value_string rtcp_app_poc1_floor_cnt_type_vals[] = { { TBCP_BURST_REQUEST, "TBCP Talk Burst Request"}, { TBCP_BURST_GRANTED, "TBCP Talk Burst Granted"}, { TBCP_BURST_TAKEN_EXPECT_NO_REPLY, "TBCP Talk Burst Taken (no ack expected)"}, { TBCP_BURST_DENY, "TBCP Talk Burst Deny"}, { TBCP_BURST_RELEASE, "TBCP Talk Burst Release"}, { TBCP_BURST_IDLE, "TBCP Talk Burst Idle"}, { TBCP_BURST_REVOKE, "TBCP Talk Burst Revoke"}, { TBCP_BURST_ACKNOWLEDGMENT, "TBCP Talk Burst Acknowledgement"}, { TBCP_QUEUE_STATUS_REQUEST, "TBCP Queue Status Request"}, { TBCP_QUEUE_STATUS_RESPONSE, "TBCP Queue Status Response"}, { TBCP_DISCONNECT, "TBCP Disconnect"}, { TBCP_CONNECT, "TBCP Connect"}, { TBCP_BURST_TAKEN_EXPECT_REPLY, "TBCP Talk Burst Taken (ack expected)"}, { 0, NULL } }; static const value_string rtcp_app_poc1_reason_code1_vals[] = { { 1, "Another PoC User has permission"}, { 2, "Internal PoC server error"}, { 3, "Only one participant in the group"}, { 4, "Retry-after timer has not expired"}, { 5, "Listen only"}, { 0, NULL } }; static const value_string rtcp_app_poc1_reason_code2_vals[] = { { 1, "Only one user"}, { 2, "Talk burst too long"}, { 3, "No permission to send a Talk Burst"}, { 4, "Talk burst pre-empted"}, { 0, NULL } }; static const value_string rtcp_app_poc1_reason_code_ack_vals[] = { { 0, "Accepted"}, { 1, "Busy"}, { 2, "Not accepted"}, { 0, NULL } }; static const value_string rtcp_app_poc1_conn_sess_type_vals[] = { { 0, "None"}, { 1, "1-to-1"}, { 2, "Ad-hoc"}, { 3, "Pre-arranged"}, { 4, "Chat"}, { 0, NULL } }; static const value_string rtcp_app_poc1_qsresp_priority_vals[] = { { 0, "No priority (un-queued)"}, { 1, "Normal priority"}, { 2, "High priority"}, { 3, "Pre-emptive priority"}, { 0, NULL } }; /* 3GPP 29.414 RTP Multiplexing */ static const value_string rtcp_app_mux_selection_vals[] = { { 0, "No multiplexing applied"}, { 1, "Multiplexing without RTP header compression applied"}, { 2, "Multiplexing with RTP header compression applied"}, { 3, "Reserved"}, { 0, NULL} }; /* RFC 4585 and RFC 5104 */ static const value_string rtcp_rtpfb_fmt_vals[] = { { 1, "Generic negative acknowledgement (NACK)"}, { 3, "Temporary Maximum Media Stream Bit Rate Request (TMMBR)"}, { 4, "Temporary Maximum Media Stream Bit Rate Notification (TMMBN)"}, { 15, "Transport-wide Congestion Control (Transport-cc)"}, /*https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01*/ { 31, "Reserved for future extensions"}, { 0, NULL } }; static const value_string rtcp_psfb_fmt_vals[] = { { 1, "Picture Loss Indication"}, { 2, "Slice Loss Indication"}, { 3, "Reference Picture Selection Indication"}, { 4, "Full Intra Request (FIR) Command"}, { 5, "Temporal-Spatial Trade-off Request (TSTR)"}, { 6, "Temporal-Spatial Trade-off Notification (TSTN)"}, { 7, "Video Back Channel Message (VBCM)"}, { 15, "Application Layer Feedback"}, { 31, "Reserved for future extensions"}, { 0, NULL } }; static const value_string rtcp_psfb_fmt_summary_vals[] = { { 1, "PLI"}, { 2, "SLI"}, { 3, "RPSI"}, { 4, "FIR"}, { 5, "TSTR"}, { 6, "TSTN"}, { 7, "VBCM"}, { 15, "ALFB"}, { 31, "Reserved"}, { 0, NULL } }; /* Microsoft Profile Specific Extension Types */ static const value_string rtcp_ms_profile_extension_vals[] = { { 1, "MS - Estimated Bandwidth"}, { 4, "MS - Packet Loss Notification"}, { 5, "MS - Video Preference"}, { 6, "MS - Padding"}, { 7, "MS - Policy Server Bandwidth"}, { 8, "MS - TURN Server Bandwidth"}, { 9, "MS - Audio Healer Metrics"}, { 10, "MS - Receiver-side Bandwidth Limit"}, { 11, "MS - Packet Train Packet"}, { 12, "MS - Peer Info Exchange"}, { 13, "MS - Network Congestion Notification"}, { 14, "MS - Modality Send Bandwidth Limit"}, { 0, NULL } }; static const value_string rtcp_ssrc_values[] = { { 0xFFFFFFFF, "SOURCE_NONE" }, { 0xFFFFFFFE, "SOURCE_ANY" }, { 0, NULL } }; /* TS 24.380 V17.7.0 */ static const value_string rtcp_mcpt_subtype_vals[] = { { 0x00, "Floor Request" }, { 0x01, "Floor Granted" }, { 0x02, "Floor Taken" }, { 0x03, "Floor Deny" }, { 0x04, "Floor Release" }, { 0x05, "Floor Idle" }, { 0x06, "Floor Revoke" }, { 0x08, "Floor Queue Position Request" }, { 0x09, "Floor Queue Position Info" }, { 0x0a, "Floor Ack" }, { 0x0b, "Unicast Media Flow Control" }, { 0x0e, "Floor Queued Cancel" }, { 0x0f, "Floor Release Multi Talker" }, { 0x11, "Floor Granted(ack req)" }, { 0x12, "Floor Taken(ack req)" }, { 0x13, "Floor Deny(ack req)" }, { 0x14, "Floor Release(ack req)" }, { 0x15, "Floor Idle(ack req)" }, { 0x19, "Floor Queue Position Info(ack req)" }, { 0x1b, "Unicast Media Flow Control(ack req)" }, { 0x1e, "Floor Queued Cancel(ack req)" }, { 0, NULL } }; /* TS 24.380 V17.7.0 */ static const value_string rtcp_mccp_subtype_vals[] = { { 0x00, "Map Group To Bearer" }, { 0x01, "Unmap Group To Bearer" }, { 0x02, "Application Paging" }, { 0x03, "Bearer Announcement" }, { 0, NULL } }; /* TS 24.380 V17.7.0 */ static const value_string rtcp_mcpt_field_id_vals[] = { { 0, "Floor Priority" }, { 1, "Duration" }, { 2, "Reject Cause" }, { 3, "Queue Info" }, { 4, "Granted Party's Identity" }, { 5, "Permission to Request the Floor" }, { 6, "User ID" }, { 7, "Queue Size" }, { 8, "Message Sequence-Number" }, { 9, "Queued User ID" }, { 10, "Source" }, { 11, "Track Info" }, { 12, "Message Type" }, { 13, "Floor Indicator" }, { 14, "SSRC" }, { 15, "List of Granted Users" }, { 16, "List of SSRCs" }, { 17, "Functional Alias" }, { 18, "List of Functional Aliases" }, { 19, "Location" }, { 20, "List of Locations" }, { 21, "Queued Floor Requests Purpose" }, { 22, "List of Queued Users" }, { 23, "Response State" }, { 24, "Media Flow Control Indicator" }, { 102, "Floor Priority" }, { 103, "Duration" }, { 104, "Reject Cause" }, { 105, "Queue Info" }, { 106, "Granted Party's Identity" }, { 108, "Permission to Request the Floor" }, { 109, "User ID" }, { 110, "Queue Size" }, { 111, "Message SequenceNumber" }, { 112, "Queued User ID" }, { 113, "Source" }, { 114, "Track Info" }, { 115, "Message Type" }, { 116, "Floor Indicator" }, { 0, NULL } }; /* TS 24.380 V17.7.0 */ static const value_string rtcp_mccp_field_id_vals[] = { { 0, "Subchannel" }, { 1, "TMGI" }, { 2, "MCPTT Group ID" }, { 3, "Monitoring State" }, { 0, NULL } }; /* RTCP header fields */ static int proto_rtcp = -1; static int proto_srtcp = -1; static int hf_rtcp_version = -1; static int hf_rtcp_padding = -1; static int hf_rtcp_rc = -1; static int hf_rtcp_sc = -1; static int hf_rtcp_pt = -1; static int hf_rtcp_length = -1; static int hf_rtcp_ssrc_sender = -1; static int hf_rtcp_ssrc_media_source = -1; static int hf_rtcp_ntp = -1; static int hf_rtcp_ntp_msw = -1; static int hf_rtcp_ntp_lsw = -1; static int hf_rtcp_timebase_indicator = -1; static int hf_rtcp_identity = -1; static int hf_rtcp_stream_id = -1; static int hf_rtcp_as_timestamp = -1; static int hf_rtcp_rtp_timestamp = -1; static int hf_rtcp_sender_pkt_cnt = -1; static int hf_rtcp_sender_oct_cnt = -1; static int hf_rtcp_ssrc_source = -1; static int hf_rtcp_ssrc_fraction = -1; static int hf_rtcp_ssrc_cum_nr = -1; static int hf_rtcp_ssrc_discarded = -1; /* First the 32 bit number, then the split * up 16 bit values */ /* These two are added to a subtree */ static int hf_rtcp_ssrc_ext_high_seq = -1; static int hf_rtcp_ssrc_high_seq = -1; static int hf_rtcp_ssrc_high_cycles = -1; static int hf_rtcp_ssrc_jitter = -1; static int hf_rtcp_ssrc_lsr = -1; static int hf_rtcp_ssrc_dlsr = -1; /* static int hf_rtcp_ssrc_csrc = -1; */ static int hf_rtcp_sdes_type = -1; static int hf_rtcp_sdes_length = -1; static int hf_rtcp_sdes_text = -1; static int hf_rtcp_sdes_prefix_len = -1; static int hf_rtcp_sdes_prefix_string = -1; static int hf_rtcp_subtype = -1; static int hf_rtcp_name_ascii = -1; static int hf_rtcp_app_data = -1; static int hf_rtcp_app_data_str = -1; static int hf_rtcp_fsn = -1; static int hf_rtcp_blp = -1; static int hf_rtcp_padding_count = -1; static int hf_rtcp_padding_data = -1; static int hf_rtcp_profile_specific_extension_type = -1; static int hf_rtcp_profile_specific_extension_length = -1; static int hf_rtcp_profile_specific_extension = -1; static int hf_rtcp_app_poc1 = -1; static int hf_rtcp_app_poc1_sip_uri = -1; static int hf_rtcp_app_poc1_disp_name = -1; static int hf_rtcp_app_poc1_priority = -1; static int hf_rtcp_app_poc1_request_ts = -1; static int hf_rtcp_app_poc1_stt = -1; static int hf_rtcp_app_poc1_partic = -1; static int hf_rtcp_app_poc1_ssrc_granted = -1; static int hf_rtcp_app_poc1_last_pkt_seq_no = -1; static int hf_rtcp_app_poc1_ignore_seq_no = -1; static int hf_rtcp_app_poc1_reason_code1 = -1; static int hf_rtcp_app_poc1_reason1_phrase = -1; static int hf_rtcp_app_poc1_reason_code2 = -1; static int hf_rtcp_app_poc1_new_time_request = -1; static int hf_rtcp_app_poc1_ack_subtype = -1; static int hf_rtcp_app_poc1_ack_reason_code = -1; static int hf_rtcp_app_poc1_qsresp_priority = -1; static int hf_rtcp_app_poc1_qsresp_position = -1; static int hf_rtcp_app_poc1_conn_content[5] = { -1, -1, -1, -1, -1 }; static int hf_rtcp_app_poc1_conn_session_type = -1; static int hf_rtcp_app_poc1_conn_add_ind_mao = -1; static int hf_rtcp_app_poc1_conn_sdes_items[5] = { -1, -1, -1, -1, -1 }; static int hf_rtcp_app_mux = -1; static int hf_rtcp_app_mux_mux = -1; static int hf_rtcp_app_mux_cp = -1; static int hf_rtcp_app_mux_selection = -1; static int hf_rtcp_app_mux_localmuxport = -1; static int hf_rtcp_xr_block_type = -1; static int hf_rtcp_xr_block_specific = -1; static int hf_rtcp_xr_block_length = -1; static int hf_rtcp_xr_thinning = -1; static int hf_rtcp_xr_voip_metrics_burst_density = -1; static int hf_rtcp_xr_voip_metrics_gap_density = -1; static int hf_rtcp_xr_voip_metrics_burst_duration = -1; static int hf_rtcp_xr_voip_metrics_gap_duration = -1; static int hf_rtcp_xr_voip_metrics_rtdelay = -1; static int hf_rtcp_xr_voip_metrics_esdelay = -1; static int hf_rtcp_xr_voip_metrics_siglevel = -1; static int hf_rtcp_xr_voip_metrics_noiselevel = -1; static int hf_rtcp_xr_voip_metrics_rerl = -1; static int hf_rtcp_xr_voip_metrics_gmin = -1; static int hf_rtcp_xr_voip_metrics_rfactor = -1; static int hf_rtcp_xr_voip_metrics_extrfactor = -1; static int hf_rtcp_xr_voip_metrics_moslq = -1; static int hf_rtcp_xr_voip_metrics_moscq = -1; static int hf_rtcp_xr_voip_metrics_plc = -1; static int hf_rtcp_xr_voip_metrics_jbadaptive = -1; static int hf_rtcp_xr_voip_metrics_jbrate = -1; static int hf_rtcp_xr_voip_metrics_jbnominal = -1; static int hf_rtcp_xr_voip_metrics_jbmax = -1; static int hf_rtcp_xr_voip_metrics_jbabsmax = -1; static int hf_rtcp_xr_stats_loss_flag = -1; static int hf_rtcp_xr_stats_dup_flag = -1; static int hf_rtcp_xr_stats_jitter_flag = -1; static int hf_rtcp_xr_stats_ttl = -1; static int hf_rtcp_xr_beginseq = -1; static int hf_rtcp_xr_endseq = -1; static int hf_rtcp_xr_chunk_null_terminator = -1; static int hf_rtcp_xr_chunk_length = -1; static int hf_rtcp_xr_chunk_bit_vector = -1; static int hf_rtcp_xr_receipt_time_seq = -1; static int hf_rtcp_xr_stats_lost = -1; static int hf_rtcp_xr_stats_dups = -1; static int hf_rtcp_xr_stats_minjitter = -1; static int hf_rtcp_xr_stats_maxjitter = -1; static int hf_rtcp_xr_stats_meanjitter = -1; static int hf_rtcp_xr_stats_devjitter = -1; static int hf_rtcp_xr_stats_minttl = -1; static int hf_rtcp_xr_stats_maxttl = -1; static int hf_rtcp_xr_stats_meanttl = -1; static int hf_rtcp_xr_stats_devttl = -1; static int hf_rtcp_xr_timestamp = -1; static int hf_rtcp_xr_lrr = -1; static int hf_rtcp_xr_dlrr = -1; static int hf_rtcp_xr_idms_spst = -1; static int hf_rtcp_xr_idms_pt = -1; static int hf_rtcp_xr_idms_msci = -1; static int hf_rtcp_xr_idms_source_ssrc = -1; static int hf_rtcp_xr_idms_ntp_rcv_ts = -1; static int hf_rtcp_xr_idms_rtp_ts = -1; static int hf_rtcp_xr_idms_ntp_pres_ts = -1; static int hf_rtcp_length_check = -1; static int hf_rtcp_rtpfb_fmt = -1; static int hf_rtcp_rtpfb_nack_pid = -1; static int hf_rtcp_rtpfb_nack_blp = -1; static int hf_rtcp_rtpfb_transport_cc_fci_base_seq = -1; static int hf_rtcp_rtpfb_transport_cc_fci_pkt_stats_cnt = -1; static int hf_rtcp_rtpfb_transport_cc_fci_ref_time = -1; static int hf_rtcp_rtpfb_transport_cc_fci_fb_pkt_cnt = -1; static int hf_rtcp_rtpfb_transport_cc_fci_pkt_chunk = -1; static int hf_rtcp_rtpfb_transport_cc_fci_recv_delta_1_byte = -1; static int hf_rtcp_rtpfb_transport_cc_fci_recv_delta_2_bytes = -1; static int hf_rtcp_rtpfb_transport_cc_fci_recv_delta_padding = -1; static int hf_rtcp_psfb_fmt = -1; static int hf_rtcp_fci = -1; static int hf_rtcp_psfb_fir_fci_ssrc = -1; static int hf_rtcp_psfb_fir_fci_csn = -1; static int hf_rtcp_psfb_fir_fci_reserved = -1; static int hf_rtcp_psfb_sli_first = -1; static int hf_rtcp_psfb_sli_number = -1; static int hf_rtcp_psfb_sli_picture_id = -1; static int hf_rtcp_psfb_remb_fci_identifier = -1; static int hf_rtcp_psfb_remb_fci_number_ssrcs = -1; static int hf_rtcp_psfb_remb_fci_ssrc = -1; static int hf_rtcp_psfb_remb_fci_exp = -1; static int hf_rtcp_psfb_remb_fci_mantissa = -1; static int hf_rtcp_psfb_remb_fci_bitrate = -1; static int hf_rtcp_rtpfb_tmbbr_fci_ssrc = -1; static int hf_rtcp_rtpfb_tmbbr_fci_exp = -1; static int hf_rtcp_rtpfb_tmbbr_fci_mantissa = -1; static int hf_rtcp_rtpfb_tmbbr_fci_bitrate = -1; static int hf_rtcp_rtpfb_tmbbr_fci_measuredoverhead = -1; static int hf_srtcp_e = -1; static int hf_srtcp_index = -1; static int hf_srtcp_mki = -1; static int hf_srtcp_auth_tag = -1; static int hf_rtcp_xr_btxnq_begseq = -1; /* added for BT XNQ block (RFC5093) */ static int hf_rtcp_xr_btxnq_endseq = -1; static int hf_rtcp_xr_btxnq_vmaxdiff = -1; static int hf_rtcp_xr_btxnq_vrange = -1; static int hf_rtcp_xr_btxnq_vsum = -1; static int hf_rtcp_xr_btxnq_cycles = -1; static int hf_rtcp_xr_btxnq_jbevents = -1; static int hf_rtcp_xr_btxnq_tdegnet = -1; static int hf_rtcp_xr_btxnq_tdegjit = -1; static int hf_rtcp_xr_btxnq_es = -1; static int hf_rtcp_xr_btxnq_ses = -1; static int hf_rtcp_xr_btxnq_spare = -1; /* RTCP setup fields */ static int hf_rtcp_setup = -1; static int hf_rtcp_setup_frame = -1; static int hf_rtcp_setup_method = -1; /* RTCP roundtrip delay fields */ static int hf_rtcp_last_sr_timestamp_frame = -1; static int hf_rtcp_time_since_last_sr = -1; static int hf_rtcp_roundtrip_delay = -1; /* MS Profile Specific Extension Fields */ static int hf_rtcp_pse_ms_bandwidth = -1; static int hf_rtcp_pse_ms_confidence_level = -1; static int hf_rtcp_pse_ms_seq_num = -1; static int hf_rtcp_pse_ms_frame_resolution_width = -1; static int hf_rtcp_pse_ms_frame_resolution_height = -1; static int hf_rtcp_pse_ms_bitrate = -1; static int hf_rtcp_pse_ms_frame_rate = -1; static int hf_rtcp_pse_ms_concealed_frames = -1; static int hf_rtcp_pse_ms_stretched_frames = -1; static int hf_rtcp_pse_ms_compressed_frames = -1; static int hf_rtcp_pse_ms_total_frames = -1; static int hf_rtcp_pse_ms_receive_quality_state = -1; static int hf_rtcp_pse_ms_fec_distance_request = -1; static int hf_rtcp_pse_ms_last_packet_train = -1; static int hf_rtcp_pse_ms_packet_idx = -1; static int hf_rtcp_pse_ms_packet_cnt = -1; static int hf_rtcp_pse_ms_packet_train_byte_cnt = -1; static int hf_rtcp_pse_ms_inbound_bandwidth = -1; static int hf_rtcp_pse_ms_outbound_bandwidth = -1; static int hf_rtcp_pse_ms_no_cache = -1; static int hf_rtcp_pse_ms_congestion_info = -1; static int hf_rtcp_pse_ms_modality = -1; /* Microsoft PLI Extension */ static int hf_rtcp_psfb_pli_ms_request_id = -1; static int hf_rtcp_psfb_pli_ms_sfr = -1; /* Microsoft Video Source Request */ static int hf_rtcp_psfb_ms_type = -1; static int hf_rtcp_psfb_ms_length = -1; static int hf_rtcp_psfb_ms_msi = -1; static int hf_rtcp_psfb_ms_vsr_request_id = -1; static int hf_rtcp_psfb_ms_vsr_version = -1; static int hf_rtcp_psfb_ms_vsr_key_frame_request = -1; static int hf_rtcp_psfb_ms_vsr_num_entries = -1; static int hf_rtcp_psfb_ms_vsr_entry_length = -1; static int hf_rtcp_psfb_ms_vsre_payload_type = -1; static int hf_rtcp_psfb_ms_vsre_ucconfig_mode = -1; static int hf_rtcp_psfb_ms_vsre_no_sp_frames = -1; static int hf_rtcp_psfb_ms_vsre_baseline = -1; static int hf_rtcp_psfb_ms_vsre_cgs = -1; static int hf_rtcp_psfb_ms_vsre_aspect_ratio_bitmask = -1; static int hf_rtcp_psfb_ms_vsre_aspect_ratio_4by3 = -1; static int hf_rtcp_psfb_ms_vsre_aspect_ratio_16by9 = -1; static int hf_rtcp_psfb_ms_vsre_aspect_ratio_1by1 = -1; static int hf_rtcp_psfb_ms_vsre_aspect_ratio_3by4 = -1; static int hf_rtcp_psfb_ms_vsre_aspect_ratio_9by16 = -1; static int hf_rtcp_psfb_ms_vsre_aspect_ratio_20by3 = -1; static int hf_rtcp_psfb_ms_vsre_max_width = -1; static int hf_rtcp_psfb_ms_vsre_max_height = -1; static int hf_rtcp_psfb_ms_vsre_min_bitrate = -1; static int hf_rtcp_psfb_ms_vsre_bitrate_per_level = -1; static int hf_rtcp_psfb_ms_vsre_bitrate_histogram = -1; static int hf_rtcp_psfb_ms_vsre_frame_rate_mask = -1; static int hf_rtcp_psfb_ms_vsre_frame_rate_7_5 = -1; static int hf_rtcp_psfb_ms_vsre_frame_rate_12_5 = -1; static int hf_rtcp_psfb_ms_vsre_frame_rate_15 = -1; static int hf_rtcp_psfb_ms_vsre_frame_rate_25 = -1; static int hf_rtcp_psfb_ms_vsre_frame_rate_30 = -1; static int hf_rtcp_psfb_ms_vsre_frame_rate_50= -1; static int hf_rtcp_psfb_ms_vsre_frame_rate_60 = -1; static int hf_rtcp_psfb_ms_vsre_must_instances = -1; static int hf_rtcp_psfb_ms_vsre_may_instances = -1; static int hf_rtcp_psfb_ms_vsre_quality_histogram = -1; static int hf_rtcp_psfb_ms_vsre_max_pixels = -1; static int hf_rtcp_mcptt_fld_id = -1; static int hf_rtcp_mcptt_fld_len = -1; static int hf_rtcp_mcptt_fld_val = -1; static int hf_rtcp_mcptt_granted_partys_id = -1; static int hf_rtcp_app_data_padding = -1; static int hf_rtcp_mcptt_priority = -1; static int hf_rtcp_mcptt_duration = -1; static int hf_rtcp_mcptt_user_id = -1; static int hf_rtcp_mcptt_floor_ind = -1; static int hf_rtcp_mcptt_rej_cause = -1; static int hf_rtcp_mcptt_rej_cause_floor_deny; static int hf_rtcp_mcptt_rej_cause_floor_revoke; static int hf_rtcp_mcptt_rej_phrase = -1; static int hf_rtcp_mcptt_queue_pos_inf = -1; static int hf_rtcp_mcptt_queue_pri_lev = -1; static int hf_rtcp_mcptt_perm_to_req_floor = -1; static int hf_rtcp_mcptt_queue_size = -1; static int hf_rtcp_mcptt_msg_seq_num = -1; static int hf_rtcp_mcptt_queued_user_id = -1; static int hf_rtcp_mcptt_source = -1; static int hf_rtcp_mcptt_queueing_cap = -1; static int hf_rtcp_mcptt_part_type_len = -1; static int hf_rtcp_mcptt_participant_type = -1; static int hf_rtcp_mcptt_participant_ref = - 1; static int hf_rtcp_mcptt_ssrc = -1; static int hf_rtcp_mcptt_num_users = -1; static int hf_rtcp_mcptt_user_id_len = -1; static int hf_rtcp_spare16 = -1; static int hf_rtcp_mcptt_num_ssrc = -1; static int hf_rtcp_mcptt_func_alias = -1; static int hf_rtcp_mcptt_num_fas = -1; static int hf_rtcp_mcptt_fa_len = -1; static int hf_rtcp_mcptt_loc_type = -1; static int hf_rtcp_mcptt_cellid = -1; static int hf_rtcp_mcptt_enodebid = -1; static int hf_rtcp_mcptt_ecgi_eci = -1; static int hf_rtcp_mcptt_tac = -1; static int hf_rtcp_mcptt_mbms_serv_area = -1; static int hf_rtcp_mcptt_mbsfn_area_id = -1; static int hf_rtcp_mcptt_lat = -1; static int hf_rtcp_mcptt_long = -1; static int hf_rtcp_mcptt_msg_type = -1; static int hf_rtcp_mcptt_num_loc = -1; static int hf_rtcp_mcptt_str = -1; static int hf_rtcp_mccp_len = -1; static int hf_rtcp_mccp_field_id = -1; static int hf_rtcp_mcptt_group_id = -1; static int hf_rtcp_mccp_audio_m_line_no = -1; static int hf_rtcp_mccp_floor_m_line_no = -1; static int hf_rtcp_mccp_ip_version = -1; static int hf_rtcp_mccp_floor_port_no = -1; static int hf_rtcp_mccp_media_port_no = -1; static int hf_rtcp_mccp_ipv4 = -1; static int hf_rtcp_mccp_ipv6 = -1; static int hf_rtcp_mccp_tmgi = -1; static int hf_rtcp_encrypted = -1; /* RTCP fields defining a sub tree */ static gint ett_rtcp = -1; static gint ett_rtcp_sr = -1; static gint ett_rtcp_rr = -1; static gint ett_rtcp_sdes = -1; static gint ett_rtcp_bye = -1; static gint ett_rtcp_app = -1; static gint ett_rtcp_rtpfb = -1; static gint ett_rtcp_psfb = -1; static gint ett_rtcp_xr = -1; static gint ett_rtcp_fir = -1; static gint ett_rtcp_nack = -1; static gint ett_ssrc = -1; static gint ett_ssrc_item = -1; static gint ett_ssrc_ext_high = -1; static gint ett_sdes = -1; static gint ett_sdes_item = -1; static gint ett_PoC1 = -1; static gint ett_mux = -1; static gint ett_rtcp_setup = -1; static gint ett_rtcp_roundtrip_delay = -1; static gint ett_xr_block = -1; static gint ett_xr_block_contents = -1; static gint ett_xr_ssrc = -1; static gint ett_xr_loss_chunk = -1; static gint ett_poc1_conn_contents = -1; static gint ett_rtcp_nack_blp = -1; static gint ett_pse = -1; static gint ett_ms_vsr = -1; static gint ett_ms_vsr_entry = -1; static gint ett_ms_ds = -1; static gint ett_rtcp_mcpt = -1; static gint ett_rtcp_mcptt_participant_ref = -1; static gint ett_rtcp_mcptt_eci = -1; static gint ett_rtcp_mccp_tmgi = -1; static expert_field ei_rtcp_not_final_padding = EI_INIT; static expert_field ei_rtcp_bye_reason_not_padded = EI_INIT; static expert_field ei_rtcp_xr_block_length_bad = EI_INIT; static expert_field ei_rtcp_roundtrip_delay = EI_INIT; static expert_field ei_rtcp_length_check = EI_INIT; static expert_field ei_rtcp_roundtrip_delay_negative = EI_INIT; static expert_field ei_rtcp_psfb_ms_type = EI_INIT; static expert_field ei_rtcp_missing_sender_ssrc = EI_INIT; static expert_field ei_rtcp_missing_block_header = EI_INIT; static expert_field ei_rtcp_block_length = EI_INIT; static expert_field ei_srtcp_encrypted_payload = EI_INIT; static expert_field ei_rtcp_rtpfb_transportcc_bad = EI_INIT; static expert_field ei_rtcp_mcptt_unknown_fld = EI_INIT; static expert_field ei_rtcp_mcptt_location_type = EI_INIT; static expert_field ei_rtcp_appl_extra_bytes = EI_INIT; static expert_field ei_rtcp_appl_not_ascii = EI_INIT; static expert_field ei_rtcp_appl_non_conformant = EI_INIT; static expert_field ei_rtcp_appl_non_zero_pad = EI_INIT; enum default_protocol_type { RTCP_PROTO_RTCP, RTCP_PROTO_SRTCP }; static const enum_val_t rtcp_default_protocol_vals[] = { {"RTCP", "RTCP", RTCP_PROTO_RTCP}, {"SRTCP", "SRTCP", RTCP_PROTO_SRTCP}, {NULL, NULL, -1} }; static gint global_rtcp_default_protocol = RTCP_PROTO_RTCP; /* Main dissection function */ static int dissect_rtcp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data); static int dissect_srtcp(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data); /* Displaying set info */ static gboolean global_rtcp_show_setup_info = TRUE; static void show_setup_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); /* Related to roundtrip calculation (using LSR and DLSR) */ static gboolean global_rtcp_show_roundtrip_calculation = FALSE; #define MIN_ROUNDTRIP_TO_REPORT_DEFAULT 10 static guint global_rtcp_show_roundtrip_calculation_minimum = MIN_ROUNDTRIP_TO_REPORT_DEFAULT; static void remember_outgoing_sr(packet_info *pinfo, guint32 lsr); static void calculate_roundtrip_delay(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 lsr, guint32 dlsr); static void add_roundtrip_delay_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint frame, guint gap_between_reports, gint delay); enum application_specific_encoding_type { RTCP_APP_NONE, RTCP_APP_MCPTT }; static const enum_val_t rtcp_application_specific_encoding_vals[] = { {"None", "None", RTCP_APP_NONE}, {"MCPT", "MCPT", RTCP_APP_MCPTT}, {NULL, NULL, -1} }; static gint preferences_application_specific_encoding = RTCP_APP_NONE; /* Set up an RTCP conversation using the info given */ void srtcp_add_address( packet_info *pinfo, address *addr, int port, int other_port, const gchar *setup_method, guint32 setup_frame_number, struct srtp_info *srtcp_info) { address null_addr; conversation_t *p_conv; struct _rtcp_conversation_info *p_conv_data; /* * 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) { 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_UDP, port, other_port, NO_ADDR_B | (!other_port ? NO_PORT_B : 0)); /* * If not, create a new conversation. */ if ( ! p_conv ) { p_conv = conversation_new( setup_frame_number, addr, &null_addr, CONVERSATION_UDP, (guint32)port, (guint32)other_port, NO_ADDR2 | (!other_port ? NO_PORT2 : 0)); } /* Set dissector */ conversation_set_dissector(p_conv, rtcp_handle); /* * Check if the conversation has data associated with it. */ p_conv_data = (struct _rtcp_conversation_info *)conversation_get_proto_data(p_conv, proto_rtcp); /* * If not, add a new data item. */ if ( ! p_conv_data ) { /* Create conversation data */ p_conv_data = wmem_new0(wmem_file_scope(), struct _rtcp_conversation_info); conversation_add_proto_data(p_conv, proto_rtcp, p_conv_data); } /* * Update the conversation data. */ p_conv_data->setup_method_set = TRUE; (void) g_strlcpy(p_conv_data->setup_method, setup_method, MAX_RTCP_SETUP_METHOD_SIZE); p_conv_data->setup_frame_number = setup_frame_number; p_conv_data->srtcp_info = srtcp_info; } /* Set up an RTCP conversation using the info given */ void rtcp_add_address( packet_info *pinfo, address *addr, int port, int other_port, const gchar *setup_method, guint32 setup_frame_number) { srtcp_add_address(pinfo, addr, port, other_port, setup_method, setup_frame_number, NULL); } static gboolean dissect_rtcp_heur( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_ ) { unsigned int offset = 0; unsigned int first_byte; unsigned int packet_type; if (tvb_captured_length(tvb) < 2) return FALSE; /* Look at first byte */ first_byte = tvb_get_guint8(tvb, offset); /* Are version bits set to 2? */ if (((first_byte & 0xC0) >> 6) != 2) { return FALSE; } /* Look at packet type */ packet_type = tvb_get_guint8(tvb, offset + 1); /* First packet within compound packet is supposed to be a sender or receiver report. (However, see RFC 5506 which allows the use of non-compound RTCP packets in some circumstances.) - allow BYE because this happens anyway - allow APP because TBCP ("PoC1") packets aren't compound... - allow PSFB for MS */ if (!((packet_type == RTCP_SR) || (packet_type == RTCP_RR) || (packet_type == RTCP_BYE) || (packet_type == RTCP_APP) || (packet_type == RTCP_PSFB))) { return FALSE; } /* Overall length must be a multiple of 4 bytes */ if (tvb_reported_length(tvb) % 4) { return FALSE; } /* OK, dissect as RTCP */ /* XXX: This heuristic doesn't differentiate between RTCP and SRTCP. * There are some possible extra heuristics: looking to see if there's * extra length (that is not padding), looking if padding is enabled * but the last byte is inconsistent with padding, stepping through * compound packets and seeing if it looks encrypted at some point, etc. */ if (global_rtcp_default_protocol == RTCP_PROTO_RTCP) { dissect_rtcp(tvb, pinfo, tree, data); } else { dissect_srtcp(tvb, pinfo, tree, data); } return TRUE; } /* Dissect the length field. Append to this field text indicating the number of actual bytes this translates to (i.e. (raw value + 1) * 4) */ static int dissect_rtcp_length_field( proto_tree *tree, tvbuff_t *tvb, int offset) { proto_item *ti; unsigned short raw_length = tvb_get_ntohs( tvb, offset ); ti = proto_tree_add_item( tree, hf_rtcp_length, tvb, offset, 2, ENC_BIG_ENDIAN); proto_item_append_text(ti, " (%u bytes)", (raw_length+1)*4); offset += 2; return offset; } static int dissect_rtcp_nack( tvbuff_t *tvb, int offset, proto_tree *tree ) { /* Packet type = FIR (H261) */ proto_tree_add_item( tree, hf_rtcp_rc, tvb, offset, 1, ENC_BIG_ENDIAN ); offset++; /* Packet type, 8 bits = APP */ proto_tree_add_item( tree, hf_rtcp_pt, tvb, offset, 1, ENC_BIG_ENDIAN ); offset++; /* Packet length in 32 bit words minus one */ offset = dissect_rtcp_length_field(tree, tvb, offset); /* SSRC */ proto_tree_add_item( tree, hf_rtcp_ssrc_source, tvb, offset, 4, ENC_BIG_ENDIAN ); offset += 4; /* FSN, 16 bits */ proto_tree_add_item( tree, hf_rtcp_fsn, tvb, offset, 2, ENC_BIG_ENDIAN ); offset += 2; /* BLP, 16 bits */ proto_tree_add_item( tree, hf_rtcp_blp, tvb, offset, 2, ENC_BIG_ENDIAN ); offset += 2; return offset; } static int dissect_rtcp_rtpfb_tmmbr( tvbuff_t *tvb, int offset, proto_tree *rtcp_tree, proto_item *top_item, int num_fci, int is_notification) { guint8 exp; guint32 mantissa; proto_tree *fci_tree; if (is_notification == 1) { fci_tree = proto_tree_add_subtree_format( rtcp_tree, tvb, offset, 8, ett_ssrc, NULL, "TMMBN %d", num_fci ); } else { fci_tree = proto_tree_add_subtree_format( rtcp_tree, tvb, offset, 8, ett_ssrc, NULL, "TMMBR %d", num_fci ); } /* SSRC 32 bit*/ proto_tree_add_item( fci_tree, hf_rtcp_rtpfb_tmbbr_fci_ssrc, tvb, offset, 4, ENC_BIG_ENDIAN ); offset += 4; /* Exp 6 bit*/ proto_tree_add_item( fci_tree, hf_rtcp_rtpfb_tmbbr_fci_exp, tvb, offset, 1, ENC_BIG_ENDIAN ); exp = (tvb_get_guint8(tvb, offset) & 0xfc) >> 2; /* Mantissa 17 bit*/ proto_tree_add_item( fci_tree, hf_rtcp_rtpfb_tmbbr_fci_mantissa, tvb, offset, 3, ENC_BIG_ENDIAN ); mantissa = (tvb_get_ntohl( tvb, offset) & 0x3fffe00) >> 9; proto_tree_add_string_format_value( fci_tree, hf_rtcp_rtpfb_tmbbr_fci_bitrate, tvb, offset, 3, "", "%u*2^%u", mantissa, exp); offset += 3; /* Overhead */ proto_tree_add_item( fci_tree, hf_rtcp_rtpfb_tmbbr_fci_measuredoverhead, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; if (top_item != NULL) { proto_item_append_text(top_item, ": TMMBR: %u*2^%u", mantissa, exp); } return offset; } /* Dissect Application Specific Feedback messages */ static int dissect_rtcp_asfb_ms( tvbuff_t *tvb, int offset, proto_tree *tree, packet_info *pinfo) { guint8 num_entries; guint8 desc = 0; guint16 type; guint16 length; guint8 i; guint32 msi; guint32 min_bitrate, bitrate_per_level; proto_tree *rtcp_ms_vsr_tree; proto_tree *rtcp_ms_vsr_entry_tree; proto_tree *rtcp_ms_ds_tree; proto_item *item, *type_item; type = tvb_get_ntohs(tvb, offset); type_item = proto_tree_add_item( tree, hf_rtcp_psfb_ms_type, tvb, offset, 2, ENC_BIG_ENDIAN ); offset += 2; length = tvb_get_ntohs(tvb, offset) - 4; proto_tree_add_item( tree, hf_rtcp_psfb_ms_length, tvb, offset, 2, ENC_BIG_ENDIAN ); offset += 2; if (type == 1) { rtcp_ms_vsr_tree = proto_tree_add_subtree(tree, tvb, offset, length, ett_ms_vsr, &item, "MS Video Source Request"); col_append_fstr(pinfo->cinfo, COL_INFO,"( MS-VSR )"); item = proto_tree_add_item( rtcp_ms_vsr_tree, hf_rtcp_psfb_ms_msi, tvb, offset, 4, ENC_BIG_ENDIAN ); msi = tvb_get_ntohl (tvb, offset); /* Decode if it is NONE or ANY and add to line */ proto_item_append_text(item," %s", val_to_str_const(msi, rtcp_ssrc_values, "")); offset += 4; proto_tree_add_item( rtcp_ms_vsr_tree, hf_rtcp_psfb_ms_vsr_request_id, tvb, offset, 2, ENC_BIG_ENDIAN ); offset += 2; /* 2 reserved bytes */ offset += 2; proto_tree_add_item( rtcp_ms_vsr_tree, hf_rtcp_psfb_ms_vsr_version, tvb, offset, 1, ENC_BIG_ENDIAN ); offset++; proto_tree_add_item( rtcp_ms_vsr_tree, hf_rtcp_psfb_ms_vsr_key_frame_request, tvb, offset, 1, ENC_BIG_ENDIAN ); offset++; num_entries = tvb_get_guint8(tvb, offset); proto_tree_add_item( rtcp_ms_vsr_tree, hf_rtcp_psfb_ms_vsr_num_entries, tvb, offset, 1, ENC_BIG_ENDIAN ); offset++; proto_tree_add_item( rtcp_ms_vsr_tree, hf_rtcp_psfb_ms_vsr_entry_length, tvb, offset, 1, ENC_BIG_ENDIAN ); offset++; /* 4 reserved bytes */ offset += 4; while (num_entries-- && tvb_captured_length_remaining (tvb, offset) >= 0x44) { rtcp_ms_vsr_entry_tree = proto_tree_add_subtree_format(rtcp_ms_vsr_tree, tvb, offset, 0x44, ett_ms_vsr_entry, NULL, "MS Video Source Request Entry #%d", ++desc); proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_payload_type, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_ucconfig_mode, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_no_sp_frames, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_baseline, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_cgs, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_aspect_ratio_bitmask, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_aspect_ratio_20by3, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_aspect_ratio_9by16, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_aspect_ratio_3by4, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_aspect_ratio_1by1, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_aspect_ratio_16by9, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_aspect_ratio_4by3, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_max_width, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_max_height, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_min_bitrate, tvb, offset, 4, ENC_BIG_ENDIAN); min_bitrate = tvb_get_ntohl (tvb, offset); offset += 4; /* 4 Reserved bytes */ offset += 4; proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_bitrate_per_level, tvb, offset, 4, ENC_BIG_ENDIAN); bitrate_per_level = tvb_get_ntohl (tvb, offset); offset += 4; for (i = 0 ; i < 10 ; i++) { item = proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_bitrate_histogram, tvb, offset, 2, ENC_BIG_ENDIAN); proto_item_prepend_text(item,"Bitrate %d - %d ", min_bitrate + i * bitrate_per_level, min_bitrate + (i + 1) * bitrate_per_level); offset += 2; } proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_frame_rate_mask, tvb, offset, 4, ENC_BIG_ENDIAN); offset +=3; /* Move to low byte of mask where valid setting are */ proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_frame_rate_60, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_frame_rate_50, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_frame_rate_30, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_frame_rate_25, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_frame_rate_15, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_frame_rate_12_5, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_frame_rate_7_5, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_must_instances, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_may_instances, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; for (i = 0 ; i < 8 ; i++) { item = proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_quality_histogram, tvb, offset, 2, ENC_BIG_ENDIAN); proto_item_prepend_text(item, "Quality Level %d ", i+1 ); offset += 2; } proto_tree_add_item (rtcp_ms_vsr_entry_tree, hf_rtcp_psfb_ms_vsre_max_pixels, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; } } else if (type == 3) { /* MS Dominant Speaker History */ rtcp_ms_ds_tree = proto_tree_add_subtree(tree, tvb, offset, length, ett_ms_ds, NULL, "MS Dominant Speaker History"); col_append_fstr(pinfo->cinfo, COL_INFO,"( MS-DSH )"); while (length-- && tvb_captured_length_remaining (tvb, offset) >= 4) { item = proto_tree_add_item( rtcp_ms_ds_tree, hf_rtcp_psfb_ms_msi, tvb, offset, 4, ENC_BIG_ENDIAN ); msi = tvb_get_ntohl (tvb, offset); proto_item_append_text(item," %s", val_to_str_const(msi, rtcp_ssrc_values, "")); offset += 4; length --; } } else { expert_add_info(pinfo, type_item, &ei_rtcp_psfb_ms_type); offset += tvb_captured_length_remaining (tvb, offset); } return offset; } static int dissect_rtcp_psfb_remb( tvbuff_t *tvb, int offset, proto_tree *rtcp_tree, proto_item *top_item, int num_fci, int *read_fci) { guint exp, indexSsrcs; guint8 numberSsrcs; guint64 mantissa, bitrate; proto_tree *fci_tree; fci_tree = proto_tree_add_subtree_format( rtcp_tree, tvb, offset, 8, ett_ssrc, NULL, "REMB %d", num_fci ); /* Unique identifier 'REMB' */ proto_tree_add_item( fci_tree, hf_rtcp_psfb_remb_fci_identifier, tvb, offset, 4, ENC_ASCII ); offset += 4; /* Number of ssrcs - they will each be parsed below */ proto_tree_add_item( fci_tree, hf_rtcp_psfb_remb_fci_number_ssrcs, tvb, offset, 1, ENC_BIG_ENDIAN ); numberSsrcs = tvb_get_guint8( tvb, offset); offset += 1; /* Exp 6 bit*/ proto_tree_add_item( fci_tree, hf_rtcp_psfb_remb_fci_exp, tvb, offset, 1, ENC_BIG_ENDIAN ); exp = (tvb_get_guint8(tvb, offset) & 0xfc) ; exp = exp >> 2; /* Mantissa 18 bit*/ proto_tree_add_item( fci_tree, hf_rtcp_psfb_remb_fci_mantissa, tvb, offset, 3, ENC_BIG_ENDIAN ); mantissa = (tvb_get_ntohl( tvb, offset - 1) & 0x0003ffff); bitrate = mantissa << exp; proto_tree_add_string_format_value( fci_tree, hf_rtcp_psfb_remb_fci_bitrate, tvb, offset, 3, "", "%" PRIu64, bitrate); offset += 3; for (indexSsrcs = 0; indexSsrcs < numberSsrcs; indexSsrcs++) { /* SSRC 32 bit*/ proto_tree_add_item( fci_tree, hf_rtcp_psfb_remb_fci_ssrc, tvb, offset, 4, ENC_BIG_ENDIAN ); offset += 4; } if (top_item != NULL) { proto_item_append_text(top_item, ": REMB: max bitrate=%" PRIu64, bitrate); } *read_fci = 2 + (numberSsrcs); return offset; } #define RTCP_HEADER_LENGTH 12 static int dissect_rtcp_rtpfb_transport_cc( tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *rtcp_tree, guint *padding_set, int pkt_len) { proto_tree *fci_tree, *pkt_chunk_tree, *recv_delta_tree; proto_item *item = NULL; guint8 *delta_array; guint16 *pkt_seq_array; guint32 i, pkt_base_seq, pkt_seq_num, pkt_count, delta_index = 0; gint fci_length = pkt_len - RTCP_HEADER_LENGTH; int padding_length = offset; fci_tree = proto_tree_add_subtree_format( rtcp_tree, tvb, offset, fci_length, ett_ssrc, NULL, "Transport-cc" ); /* base sequence number */ proto_tree_add_item_ret_uint( fci_tree, hf_rtcp_rtpfb_transport_cc_fci_base_seq, tvb, offset, 2, ENC_BIG_ENDIAN, &pkt_base_seq ); offset += 2; pkt_seq_num = pkt_base_seq; /* packet status count */ proto_tree_add_item_ret_uint( fci_tree, hf_rtcp_rtpfb_transport_cc_fci_pkt_stats_cnt, tvb, offset, 2, ENC_BIG_ENDIAN, &pkt_count ); offset += 2; delta_array = wmem_alloc0_array( pinfo->pool, gint8, pkt_count ); pkt_seq_array = wmem_alloc0_array( pinfo->pool, gint16, pkt_count ); /* reference time */ proto_tree_add_item( fci_tree, hf_rtcp_rtpfb_transport_cc_fci_ref_time, tvb, offset, 3, ENC_BIG_ENDIAN ); offset += 3; /* feedback packet count */ proto_tree_add_item( fci_tree, hf_rtcp_rtpfb_transport_cc_fci_fb_pkt_cnt, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; /* packet chunk */ pkt_chunk_tree = proto_tree_add_subtree_format( fci_tree, tvb, offset, 0, ett_ssrc, NULL, "Packet Chunks" ); for (i = 0; i < pkt_count; ) { guint32 chunk = 0; item = proto_tree_add_item_ret_uint( pkt_chunk_tree, hf_rtcp_rtpfb_transport_cc_fci_pkt_chunk, tvb, offset, 2, ENC_BIG_ENDIAN, &chunk ); /* Packet Status Symbols */ /** * 00 Packet not received * 01 Packet received, small delta * 10 Packet received, large or negative delta * 11 [Reserved] */ if ( !(chunk & 0x8000) ) { /* Run length chunk, first bit is zero */ guint length = chunk & 0x1FFF; if ( length <= 0 || pkt_count - delta_index < length ) { /* Malformed packet (zero or too many packets), stop parsing. */ proto_tree_add_expert(pkt_chunk_tree, pinfo, &ei_rtcp_rtpfb_transportcc_bad, tvb, offset, 2); offset += 2; return offset; } if ( !(chunk & 0x6000) ) { proto_item_append_text( item, " [Run Length Chunk] Packet not received. Length : %d", length); pkt_seq_num += length; } else if ( chunk & 0x2000 ) { proto_item_append_text( item, " [Run Length Chunk] Small Delta. Length : %d", length); for (guint j = 0; j < length; j++) { /*1 means 1 byte delta, 2 means 2 bytes delta*/ delta_array[delta_index+j] = 1; pkt_seq_array[delta_index+j] = pkt_seq_num++; } delta_index += length; } else if ( chunk & 0x4000 ) { proto_item_append_text( item, " [Run Length Chunk] Large or Negative Delta. Length : %d", length); for (guint j = 0; j < length; j++) { delta_array[delta_index+j] = 2; pkt_seq_array[delta_index+j] = pkt_seq_num++; } delta_index += length; } else { proto_item_append_text( item, " [Run Length Chunk] [Reserved]. Length : %d", length); pkt_seq_num += length; } i += length; } else { wmem_strbuf_t* status = wmem_strbuf_new(pinfo->pool, "|"); /* Status Vector Chunk, first bit is one */ if ( !(chunk & 0x4000) ) { /* 1 bit symbols */ int data = chunk & 0x3FFF; int chunk_count = 14; for (int k = 0; k < chunk_count; k++) { if ( (data & (0x2000>>k)) == 0 ) { if ( i + k < pkt_count ) { wmem_strbuf_append(status, " N |"); pkt_seq_num++; } else { /* padding */ wmem_strbuf_append(status, " _ |"); } } else { if (delta_index >= pkt_count) { /* Malformed packet (too many status packets). */ proto_tree_add_expert(pkt_chunk_tree, pinfo, &ei_rtcp_rtpfb_transportcc_bad, tvb, offset, 2); offset += 2; return offset; } wmem_strbuf_append(status, " R |"); delta_array[delta_index] = 1; pkt_seq_array[delta_index] = pkt_seq_num++; delta_index++; } } proto_item_append_text( item, " [1 bit Status Vector Chunk]: %s", wmem_strbuf_get_str(status)); i += chunk_count; } else { /* 2 bits symbols */ int chunk_count = 7; int data = chunk & 0x3FFF; for (int k = 0; k < chunk_count; k++) { switch ( (data & (0x3000 >> (2*k))) >> ( 2 * (6-k) ) ) { case 0: /*00 packet not received*/ if ( i + k < pkt_count ) { wmem_strbuf_append(status, " NR |"); pkt_seq_num++; } else { /*padding*/ wmem_strbuf_append(status, " __ |"); } break; case 1: /*01 Packet received, small delta*/ if (delta_index >= pkt_count) { /* Malformed packet (too many status packets). */ proto_tree_add_expert(pkt_chunk_tree, pinfo, &ei_rtcp_rtpfb_transportcc_bad, tvb, offset, 2); offset += 2; return offset; } wmem_strbuf_append(status, " SD |"); delta_array[delta_index] = 1; pkt_seq_array[delta_index] = pkt_seq_num++; delta_index++; break; case 2: /*10 Packet received, large or negative delta*/ if (delta_index >= pkt_count) { /* Malformed packet (too many status packets). */ proto_tree_add_expert(pkt_chunk_tree, pinfo, &ei_rtcp_rtpfb_transportcc_bad, tvb, offset, 2); offset += 2; return offset; } wmem_strbuf_append(status, " LD |"); delta_array[delta_index] = 2; pkt_seq_array[delta_index] = pkt_seq_num++; delta_index++; break; case 3: /*11 packet received, w/o(wrong? overflow?) timestamp*/ default: /*TODO: process overflow status which is not details on draft.*/ wmem_strbuf_append(status, " WO |"); pkt_seq_num++; break; } } proto_item_append_text( item, " [2 bits Status Vector Chunk]: %s", wmem_strbuf_get_str(status)); i += chunk_count; } } offset += 2; } /* recv delta */ recv_delta_tree = proto_tree_add_subtree_format( fci_tree, tvb, offset, 0, ett_ssrc, NULL, "Recv Delta" ); for (i = 0; i < pkt_count; i++ ) { if ( delta_array[i] == 1 ) { /*1 byte delta*/ guint32 delta; item = proto_tree_add_item_ret_uint( recv_delta_tree, hf_rtcp_rtpfb_transport_cc_fci_recv_delta_1_byte, tvb, offset, 1, ENC_BIG_ENDIAN, &delta ); proto_item_append_text( item, " Small Delta: [seq: %d] %lf ms", pkt_seq_array[i], delta*250.0/1000); offset += 1; } else if ( delta_array[i] == 2 ) { /*2 bytes delta*/ gint16 delta; item = proto_tree_add_item( recv_delta_tree, hf_rtcp_rtpfb_transport_cc_fci_recv_delta_2_bytes, tvb, offset, 2, ENC_BIG_ENDIAN); delta = tvb_get_ntohs(tvb, offset); if ( delta < 0 ) { proto_item_append_text( item, " Negative Delta: [seq: %d] %lf ms", pkt_seq_array[i], delta*250.0/1000 ); } else { proto_item_append_text( item, " Large Delta: [seq: %d] %lf ms", pkt_seq_array[i], delta*250.0/1000 ); } offset += 2; } else { /*End with 0*/ break; } } /* padding */ padding_length = fci_length - (offset - padding_length); if ( padding_length > 0 ) { proto_tree_add_item( recv_delta_tree, hf_rtcp_rtpfb_transport_cc_fci_recv_delta_padding, tvb, offset, padding_length, ENC_BIG_ENDIAN ); offset += padding_length; *padding_set = 0; /* consume RTCP padding here */ } /* delta_array / pkt_seq_array will be freed out of pinfo->pool */ delta_array = NULL; pkt_seq_array = NULL; return offset; } static int dissect_rtcp_rtpfb_nack( tvbuff_t *tvb, int offset, proto_tree *rtcp_tree, proto_item *top_item) { int i; int nack_num_frames_lost; proto_tree *bitfield_tree; unsigned int rtcp_rtpfb_nack_pid; unsigned int rtcp_rtpfb_nack_blp; proto_item *ti; proto_tree_add_item(rtcp_tree, hf_rtcp_rtpfb_nack_pid, tvb, offset, 2, ENC_BIG_ENDIAN); rtcp_rtpfb_nack_pid = tvb_get_ntohs(tvb, offset); offset += 2; ti = proto_tree_add_item(rtcp_tree, hf_rtcp_rtpfb_nack_blp, tvb, offset, 2, ENC_BIG_ENDIAN); rtcp_rtpfb_nack_blp = tvb_get_ntohs(tvb, offset); bitfield_tree = proto_item_add_subtree(ti, ett_rtcp_nack_blp); nack_num_frames_lost = 1; if (rtcp_rtpfb_nack_blp) { proto_item_append_text(ti, " (Frames"); for (i = 0; i < 16; i ++) { if (rtcp_rtpfb_nack_blp & (1< 12) { tvbuff_t *subtvb = tvb_new_subset_length(tvb, offset, packet_length - 12); if (dissector_try_uint (rtcp_rtpfb_dissector_table, rtcp_rtpfb_fmt, subtvb, pinfo, rtcp_tree)) return start_offset + packet_length; } /* Transport-Layer Feedback Message Elements */ counter = 0; while ((offset - start_offset) < packet_length) { counter++; if (rtcp_rtpfb_fmt == 1) { offset = dissect_rtcp_rtpfb_nack(tvb, offset, rtcp_tree, top_item); } else if (rtcp_rtpfb_fmt == 3) { offset = dissect_rtcp_rtpfb_tmmbr(tvb, offset, rtcp_tree, top_item, counter, 0); } else if (rtcp_rtpfb_fmt == 4) { offset = dissect_rtcp_rtpfb_tmmbr(tvb, offset, rtcp_tree, top_item, counter, 1); } else if (rtcp_rtpfb_fmt == 15) { /* Handle transport-cc (RTP Extensions for Transport-wide Congestion Control) - https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01 */ offset = dissect_rtcp_rtpfb_transport_cc( tvb, offset, pinfo, rtcp_tree, padding_set, packet_length); } else { /* Unknown FMT */ proto_tree_add_item(rtcp_tree, hf_rtcp_fci, tvb, offset, start_offset + packet_length - offset, ENC_NA ); offset = start_offset + packet_length; } } return offset; } static int dissect_rtcp_psfb( tvbuff_t *tvb, int offset, proto_tree *rtcp_tree, int packet_length, proto_item *top_item _U_, packet_info *pinfo _U_) { unsigned int counter; unsigned int num_fci; unsigned int read_fci; proto_tree *fci_tree; proto_item *ti; unsigned int rtcp_psfb_fmt; int base_offset = offset; int i; /* Payload-specific FB message */ /* Feedback message type (FMT): 5 bits */ proto_tree_add_item( rtcp_tree, hf_rtcp_psfb_fmt, tvb, offset, 1, ENC_BIG_ENDIAN ); rtcp_psfb_fmt = (tvb_get_guint8(tvb, offset) & 0x1f); col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str_const(rtcp_psfb_fmt, rtcp_psfb_fmt_summary_vals, "Unknown")); offset++; /* Packet type, 8 bits */ proto_tree_add_item( rtcp_tree, hf_rtcp_pt, tvb, offset, 1, ENC_BIG_ENDIAN ); offset++; /* Packet length in 32 bit words MINUS one, 16 bits */ num_fci = (tvb_get_ntohs(tvb, offset) - 2); offset = dissect_rtcp_length_field(rtcp_tree, tvb, offset); /* SSRC of packet sender, 32 bits */ proto_tree_add_item( rtcp_tree, hf_rtcp_ssrc_sender, tvb, offset, 4, ENC_BIG_ENDIAN ); offset += 4; /* SSRC of media source, 32 bits */ ti = proto_tree_add_item( rtcp_tree, hf_rtcp_ssrc_media_source, tvb, offset, 4, ENC_BIG_ENDIAN ); /* Decode if it is NONE or ANY and add to line */ proto_item_append_text(ti," %s", val_to_str_const(tvb_get_ntohl(tvb,offset), rtcp_ssrc_values, "")); offset += 4; /* Check if we have a type specific dissector, * if we do, just return from here */ if (packet_length > 12) { tvbuff_t *subtvb = tvb_new_subset_length(tvb, offset, packet_length - 12); if (dissector_try_uint (rtcp_psfb_dissector_table, rtcp_psfb_fmt, subtvb, pinfo, rtcp_tree)) return base_offset + packet_length; } /* Feedback Control Information (FCI) */ counter = 0; read_fci = 0; while ( read_fci < num_fci ) { switch (rtcp_psfb_fmt) { case 1: /* Picture Loss Indications (PLI) */ { /* Handle MS PLI Extension */ fci_tree = proto_tree_add_subtree_format( rtcp_tree, tvb, offset, 12, ett_ssrc, NULL, "MS PLI"); proto_tree_add_item( fci_tree, hf_rtcp_psfb_pli_ms_request_id, tvb, offset, 2, ENC_BIG_ENDIAN ); offset += 2; /* 2 reserved bytes */ offset += 2; for (i = 0 ; i < 8 ; i++) { ti = proto_tree_add_item( fci_tree, hf_rtcp_psfb_pli_ms_sfr, tvb, offset, 1, ENC_BIG_ENDIAN ); proto_item_prepend_text(ti,"PRID %d - %d ", i * 8, (i+1) * 8 - 1); offset++; } read_fci += 3; break; } case 2: /* Slice Loss Indication (SLI) */ /* Handle SLI */ fci_tree = proto_tree_add_subtree_format( rtcp_tree, tvb, offset, 4, ett_ssrc, NULL, "SLI %u", ++counter ); proto_tree_add_item( fci_tree, hf_rtcp_psfb_sli_first, tvb, offset, 4, ENC_BIG_ENDIAN ); proto_tree_add_item( fci_tree, hf_rtcp_psfb_sli_number, tvb, offset, 4, ENC_BIG_ENDIAN ); proto_tree_add_item( fci_tree, hf_rtcp_psfb_sli_picture_id, tvb, offset, 4, ENC_BIG_ENDIAN ); offset +=4; read_fci++; break; case 4: /* Handle FIR */ { /* Create a new subtree for a length of 8 bytes */ fci_tree = proto_tree_add_subtree_format( rtcp_tree, tvb, offset, 8, ett_ssrc, NULL, "FIR %u", ++counter ); /* SSRC 32 bit*/ proto_tree_add_item( fci_tree, hf_rtcp_psfb_fir_fci_ssrc, tvb, offset, 4, ENC_BIG_ENDIAN ); offset += 4; /* Command Sequence Number 8 bit*/ proto_tree_add_item( fci_tree, hf_rtcp_psfb_fir_fci_csn, tvb, offset, 1, ENC_BIG_ENDIAN ); /*proto_tree_add_item( ssrc_tree, hf_rtcp_ssrc_source, tvb, offset, 4, ENC_BIG_ENDIAN );*/ offset += 1; /* Reserved 24 bit*/ proto_tree_add_item( fci_tree, hf_rtcp_psfb_fir_fci_reserved, tvb, offset, 3, ENC_BIG_ENDIAN ); offset += 3; read_fci += 2; break; } case 15: { /* * Handle Application Layer Feedback messages. * * XXX - how do we determine how to interpret these? * * REMB (Receiver Estimated Maximum Bitrate) is, according * to section 2.3 "Signaling of use of this extension" of * https://tools.ietf.org/html/draft-alvestrand-rmcat-remb-03, * indicated as an SDP option when the session is set up. * * MS-RTP is, according to MS-RTP and according to MS-SDPEXT * section 3.1.5.30.2 "a=rtcp-fb attribute", indicated as an * SDP option when the session is set up. * * Those would work if we have the SDP setup traffic and parse * the a=rtcp-fb attribute, but if we don't, we'd need to have * the user specify it somehow. */ guint32 magic_value = tvb_get_ntohl( tvb, offset); /* look for string literal 'REMB' which is 0x52454d42 hex */ if (magic_value == 0x52454d42) { /* Handle REMB (Receiver Estimated Maximum Bitrate) - https://tools.ietf.org/html/draft-alvestrand-rmcat-remb-00 */ offset = dissect_rtcp_psfb_remb(tvb, offset, rtcp_tree, top_item, counter, &read_fci); } else { /* Handle MS Application Layer Feedback Messages - MS-RTP */ offset = dissect_rtcp_asfb_ms(tvb, offset, rtcp_tree, pinfo); read_fci = num_fci; /* Consume all the bytes. */ } break; } case 3: /* Reference Picture Selection Indication (RPSI) - Not decoded*/ default: /* Consume anything left so it doesn't make an infinite loop. */ read_fci = num_fci; break; } } /* Append undecoded FCI information */ if ((packet_length - (offset - base_offset)) > 0) { proto_tree_add_item( rtcp_tree, hf_rtcp_fci, tvb, offset, packet_length - (offset - base_offset), ENC_NA ); offset = base_offset + packet_length; } return offset; } static int dissect_rtcp_fir( tvbuff_t *tvb, int offset, proto_tree *tree ) { /* Packet type = FIR (H261) */ proto_tree_add_item( tree, hf_rtcp_rc, tvb, offset, 1, ENC_BIG_ENDIAN ); offset++; /* Packet type, 8 bits = APP */ proto_tree_add_item( tree, hf_rtcp_pt, tvb, offset, 1, ENC_BIG_ENDIAN ); offset++; /* Packet length in 32 bit words minus one */ offset = dissect_rtcp_length_field(tree, tvb, offset); /* SSRC */ proto_tree_add_item( tree, hf_rtcp_ssrc_source, tvb, offset, 4, ENC_BIG_ENDIAN ); offset += 4; return offset; } static int dissect_rtcp_app_poc1(tvbuff_t* tvb, packet_info* pinfo, int offset, proto_tree* tree, int packet_len, proto_item* subtype_item, guint rtcp_subtype) { /* PoC1 Application */ guint item_len; guint8 t2timer_code, participants_code; guint sdes_type; proto_tree* PoC1_tree; proto_item* PoC1_item; int padding; proto_item_append_text(subtype_item, " %s", val_to_str(rtcp_subtype, rtcp_app_poc1_floor_cnt_type_vals, "unknown (%u)")); col_add_fstr(pinfo->cinfo, COL_INFO, "(PoC1) %s", val_to_str(rtcp_subtype, rtcp_app_poc1_floor_cnt_type_vals, "unknown (%u)")); offset += 4; packet_len -= 4; if (packet_len == 0) return offset; /* No more data */ /* Create a subtree for the PoC1 Application items; we don't yet know the length */ /* Top-level poc tree */ PoC1_item = proto_tree_add_item(tree, hf_rtcp_app_poc1, tvb, offset, packet_len, ENC_NA); PoC1_tree = proto_item_add_subtree(PoC1_item, ett_PoC1); /* Dissect it according to its subtype */ switch (rtcp_subtype) { case TBCP_BURST_REQUEST: { guint8 code; guint16 priority; /* Both items here are optional */ if (tvb_reported_length_remaining(tvb, offset) == 0) { return offset; } /* Look for a code in the first byte */ code = tvb_get_guint8(tvb, offset); offset += 1; /* Priority (optional) */ if (code == 102) { item_len = tvb_get_guint8(tvb, offset); offset += 1; if (item_len != 2) /* SHALL be 2 */ return offset; priority = tvb_get_ntohs(tvb, offset); proto_tree_add_item(PoC1_tree, hf_rtcp_app_poc1_priority, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; col_append_fstr(pinfo->cinfo, COL_INFO, " \"%s\"", val_to_str_const(priority, rtcp_app_poc1_qsresp_priority_vals, "Unknown")); /* Look for (optional) next code */ if (tvb_reported_length_remaining(tvb, offset) == 0) { return offset; } code = tvb_get_guint8(tvb, offset); offset += 1; } /* Request timestamp (optional) */ if (code == 103) { char* buff; item_len = tvb_get_guint8(tvb, offset); offset += 1; if (item_len != 8) /* SHALL be 8 */ return offset; proto_tree_add_item_ret_time_string(PoC1_tree, hf_rtcp_app_poc1_request_ts, tvb, offset, 8, ENC_TIME_NTP | ENC_BIG_ENDIAN, pinfo->pool, &buff); offset += 8; col_append_fstr(pinfo->cinfo, COL_INFO, " ts=\"%s\"", buff); } } break; case TBCP_BURST_GRANTED: { proto_item* ti; guint16 stop_talking_time; guint16 participants; /* Stop talking timer (now mandatory) */ t2timer_code = tvb_get_guint8(tvb, offset); offset += 1; if (t2timer_code != 101) /* SHALL be 101 */ return offset; item_len = tvb_get_guint8(tvb, offset); offset += 1; if (item_len != 2) /* SHALL be 2 */ return offset; stop_talking_time = tvb_get_ntohs(tvb, offset); ti = proto_tree_add_item(PoC1_tree, hf_rtcp_app_poc1_stt, tvb, offset, 2, ENC_BIG_ENDIAN); /* Append text with meanings of value */ switch (stop_talking_time) { case 0: proto_item_append_text(ti, " unknown"); break; case 65535: proto_item_append_text(ti, " infinity"); break; default: proto_item_append_text(ti, " seconds"); break; } offset += item_len; col_append_fstr(pinfo->cinfo, COL_INFO, " stop-talking-time=%u", stop_talking_time); /* Participants (optional) */ if (tvb_reported_length_remaining(tvb, offset) == 0) { return offset; } participants_code = tvb_get_guint8(tvb, offset); offset += 1; if (participants_code != 100) /* SHALL be 100 */ return offset; item_len = tvb_get_guint8(tvb, offset); offset += 1; if (item_len != 2) /* SHALL be 2 */ return offset; participants = tvb_get_ntohs(tvb, offset); ti = proto_tree_add_item(PoC1_tree, hf_rtcp_app_poc1_partic, tvb, offset, 2, ENC_BIG_ENDIAN); /* Append text with meanings of extreme values */ switch (participants) { case 0: proto_item_append_text(ti, " (not known)"); break; case 65535: proto_item_append_text(ti, " (or more)"); break; default: break; } offset += item_len; col_append_fstr(pinfo->cinfo, COL_INFO, " participants=%u", participants); } break; case TBCP_BURST_TAKEN_EXPECT_NO_REPLY: case TBCP_BURST_TAKEN_EXPECT_REPLY: { guint16 participants; proto_item* ti; /* SSRC of PoC client */ proto_tree_add_item(PoC1_tree, hf_rtcp_app_poc1_ssrc_granted, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; packet_len -= 4; /* SDES type (must be CNAME) */ sdes_type = tvb_get_guint8(tvb, offset); proto_tree_add_item(PoC1_tree, hf_rtcp_sdes_type, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; packet_len--; if (sdes_type != RTCP_SDES_CNAME) { return offset; } /* SIP URI */ item_len = tvb_get_guint8(tvb, offset); /* Item len of 1 because it's an FT_UINT_STRING... */ proto_tree_add_item(PoC1_tree, hf_rtcp_app_poc1_sip_uri, tvb, offset, 1, ENC_ASCII | ENC_BIG_ENDIAN); offset++; col_append_fstr(pinfo->cinfo, COL_INFO, " CNAME=\"%s\"", tvb_get_string_enc(pinfo->pool, tvb, offset, item_len, ENC_ASCII)); offset += item_len; packet_len = packet_len - item_len - 1; /* In the application dependent data, the TBCP Talk Burst Taken message SHALL carry * a SSRC field and SDES items, CNAME and MAY carry SDES item NAME to identify the * PoC Client that has been granted permission to send a Talk Burst. * * The SDES item NAME SHALL be included if it is known by the PoC Server. * Therefore the length of the packet will vary depending on number of SDES items * and the size of the SDES items. */ if (packet_len == 0) return offset; /* SDES type (must be NAME if present) */ sdes_type = tvb_get_guint8(tvb, offset); if (sdes_type == RTCP_SDES_NAME) { proto_tree_add_item(PoC1_tree, hf_rtcp_sdes_type, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; packet_len--; /* Display name */ item_len = tvb_get_guint8(tvb, offset); /* Item len of 1 because it's an FT_UINT_STRING... */ proto_tree_add_item(PoC1_tree, hf_rtcp_app_poc1_disp_name, tvb, offset, 1, ENC_ASCII | ENC_BIG_ENDIAN); offset++; col_append_fstr(pinfo->cinfo, COL_INFO, " DISPLAY-NAME=\"%s\"", tvb_get_string_enc(pinfo->pool, tvb, offset, item_len, ENC_ASCII)); offset += item_len; packet_len = packet_len - item_len - 1; if (packet_len == 0) { return offset; } /* Move onto next 4-byte boundary */ if (offset % 4) { int padding2 = (4 - (offset % 4)); offset += padding2; } } /* Participants (optional) */ if (tvb_reported_length_remaining(tvb, offset) == 0) { return offset; } participants_code = tvb_get_guint8(tvb, offset); offset += 1; if (participants_code != 100) { /* SHALL be 100 */ return offset; } item_len = tvb_get_guint8(tvb, offset); offset += 1; if (item_len != 2) { /* SHALL be 2 */ return offset; } participants = tvb_get_ntohs(tvb, offset); ti = proto_tree_add_item(PoC1_tree, hf_rtcp_app_poc1_partic, tvb, offset, 2, ENC_BIG_ENDIAN); /* Append text with meanings of extreme values */ switch (participants) { case 0: proto_item_append_text(ti, " (not known)"); break; case 65535: proto_item_append_text(ti, " (or more)"); break; default: break; } col_append_fstr(pinfo->cinfo, COL_INFO, " Participants=%u", participants); offset += item_len; } break; case TBCP_BURST_DENY: { guint8 reason_code; /* Reason code */ reason_code = tvb_get_guint8(tvb, offset); proto_tree_add_item(PoC1_tree, hf_rtcp_app_poc1_reason_code1, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; packet_len--; col_append_fstr(pinfo->cinfo, COL_INFO, " reason-code=\"%s\"", val_to_str_const(reason_code, rtcp_app_poc1_reason_code1_vals, "Unknown")); /* Reason phrase */ item_len = tvb_get_guint8(tvb, offset); if (item_len != 0) { proto_tree_add_item(PoC1_tree, hf_rtcp_app_poc1_reason1_phrase, tvb, offset, 1, ENC_ASCII | ENC_BIG_ENDIAN); } offset += (item_len + 1); } break; case TBCP_BURST_RELEASE: { guint16 last_seq_no; /*guint16 ignore_last_seq_no;*/ /* Sequence number of last RTP packet in burst */ proto_tree_add_item(PoC1_tree, hf_rtcp_app_poc1_last_pkt_seq_no, tvb, offset, 2, ENC_BIG_ENDIAN); last_seq_no = tvb_get_ntohs(tvb, offset); /* Bit 16 is ignore flag */ offset += 2; proto_tree_add_item(PoC1_tree, hf_rtcp_app_poc1_ignore_seq_no, tvb, offset, 2, ENC_BIG_ENDIAN); /*ignore_last_seq_no = (tvb_get_ntohs(tvb, offset) & 0x8000);*/ /* XXX: Was the intention to also show the "ignore_last_seq_no' flag in COL_INFO ? */ col_append_fstr(pinfo->cinfo, COL_INFO, " last_rtp_seq_no=%u", last_seq_no); /* 15 bits of padding follows */ offset += 2; } break; case TBCP_BURST_IDLE: break; case TBCP_BURST_REVOKE: { /* Reason code */ guint16 reason_code = tvb_get_ntohs(tvb, offset); proto_tree_add_item(PoC1_tree, hf_rtcp_app_poc1_reason_code2, tvb, offset, 2, ENC_BIG_ENDIAN); /* The meaning of this field depends upon the reason code... */ switch (reason_code) { case 1: /* Only one user */ /* No additional info */ break; case 2: /* Talk burst too long */ /* Additional info is 16 bits with time (in seconds) client can request */ proto_tree_add_item(PoC1_tree, hf_rtcp_app_poc1_new_time_request, tvb, offset + 2, 2, ENC_BIG_ENDIAN); break; case 3: /* No permission */ /* No additional info */ break; case 4: /* Pre-empted */ /* No additional info */ break; } col_append_fstr(pinfo->cinfo, COL_INFO, " reason-code=\"%s\"", val_to_str_const(reason_code, rtcp_app_poc1_reason_code2_vals, "Unknown")); offset += 4; } break; case TBCP_BURST_ACKNOWLEDGMENT: { guint8 subtype; /* Code of message being acknowledged */ subtype = (tvb_get_guint8(tvb, offset) & 0xf8) >> 3; proto_tree_add_item(PoC1_tree, hf_rtcp_app_poc1_ack_subtype, tvb, offset, 1, ENC_BIG_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, " (for %s)", val_to_str_const(subtype, rtcp_app_poc1_floor_cnt_type_vals, "Unknown")); /* Reason code only seen if subtype was Connect */ if (subtype == TBCP_CONNECT) { proto_tree_add_item(PoC1_tree, hf_rtcp_app_poc1_ack_reason_code, tvb, offset, 2, ENC_BIG_ENDIAN); } /* 16 bits of padding follow */ offset += 4; } break; case TBCP_QUEUE_STATUS_REQUEST: break; case TBCP_QUEUE_STATUS_RESPONSE: { guint16 position; proto_item* ti; /* Priority */ proto_tree_add_item(PoC1_tree, hf_rtcp_app_poc1_qsresp_priority, tvb, offset, 1, ENC_BIG_ENDIAN); /* Queue position. 65535 indicates 'position not available' */ position = tvb_get_ntohs(tvb, offset + 1); ti = proto_tree_add_item(PoC1_tree, hf_rtcp_app_poc1_qsresp_position, tvb, offset + 1, 2, ENC_BIG_ENDIAN); if (position == 0) { proto_item_append_text(ti, " (client is un-queued)"); } if (position == 65535) { proto_item_append_text(ti, " (position not available)"); } col_append_fstr(pinfo->cinfo, COL_INFO, " position=%u", position); /* 1 bytes of padding follows */ offset += 4; } break; case TBCP_DISCONNECT: break; case TBCP_CONNECT: { proto_item* content; proto_tree* content_tree = proto_tree_add_subtree(PoC1_tree, tvb, offset, 2, ett_poc1_conn_contents, &content, "SDES item content"); gboolean contents[5]; unsigned int i; guint8 items_set = 0; guint16 items_field = tvb_get_ntohs(tvb, offset); /* Dissect each defined bit flag in the SDES item content */ for (i = 0; i < 5; i++) { proto_tree_add_item(content_tree, hf_rtcp_app_poc1_conn_content[i], tvb, offset, 2, ENC_BIG_ENDIAN); contents[i] = items_field & (1 << (15 - i)); if (contents[i]) ++items_set; } /* Show how many flags were set */ proto_item_append_text(content, " (%u items)", items_set); /* Session type */ proto_tree_add_item(PoC1_tree, hf_rtcp_app_poc1_conn_session_type, tvb, offset + 2, 1, ENC_BIG_ENDIAN); /* Additional indications */ proto_tree_add_item(PoC1_tree, hf_rtcp_app_poc1_conn_add_ind_mao, tvb, offset + 3, 1, ENC_BIG_ENDIAN); offset += 4; packet_len -= 4; /* One SDES item for every set flag in contents array */ for (i = 0; i < array_length(contents); ++i) { if (contents[i]) { guint /*sdes_type2,*/ sdes_len2; /* (sdes_type2 not currently used...). Could complain if type doesn't match expected for item... */ /*sdes_type2 = tvb_get_guint8( tvb, offset );*/ offset += 1; sdes_len2 = tvb_get_guint8(tvb, offset); /* Add SDES field indicated as present */ proto_tree_add_item(PoC1_tree, hf_rtcp_app_poc1_conn_sdes_items[i], tvb, offset, 1, ENC_BIG_ENDIAN); /* Move past field */ offset += sdes_len2 + 1; packet_len -= (sdes_len2 + 2); } } break; } default: break; } padding = 0; if (offset % 4) { padding = (4 - (offset % 4)); } if (padding) { proto_tree_add_item(PoC1_tree, hf_rtcp_app_data_padding, tvb, offset, padding, ENC_BIG_ENDIAN); offset += padding; } return offset; } static const value_string mcptt_floor_ind_vals[] = { { 0x0080, "Multi-talker" }, { 0x0100, "Temporary group call" }, { 0x0200, "Dual floor" }, { 0x0400, "Queueing supported" }, { 0x0800, "Imminent peril call" }, { 0x1000, "Emergency call" }, { 0x2000, "System call" }, { 0x4000, "Broadcast group call" }, { 0x8000, "Normal call" }, { 0, NULL }, }; static const value_string rtcp_mcptt_rej_cause_floor_deny_vals[] = { { 0x1, "Another MCPTT client has permission" }, { 0x2, "Internal floor control server error" }, { 0x3, "Only one participant" }, { 0x4, "Retry-after timer has not expired" }, { 0x5, "Receive only" }, { 0x6, "No resources available" }, { 0x7, "Queue full" }, { 0xff, "Other reason" }, { 0, NULL }, }; static const value_string rtcp_mcptt_rej_cause_floor_revoke_vals[] = { { 0x1, "Only one MCPTT client" }, { 0x2, "Media burst too long" }, { 0x3, "No permission to send a Media Burst" }, { 0x4, "Media Burst pre-empted" }, { 0x6, "No resources available" }, { 0xff, "Other reason" }, { 0, NULL }, }; static const value_string rtcp_mcptt_perm_to_req_floor_vals[] = { { 0x0, "The receiver is not permitted to request floor" }, { 0x1, "The receiver is permitted to request floor" }, { 0, NULL }, }; static const value_string rtcp_mcptt_source_vals[] = { { 0x0, "The floor participant is the source" }, { 0x1, "The participating MCPTT function is the source" }, { 0x2, "The controlling MCPTT function is the source" }, { 0x3, "The non-controlling MCPTT function is the source" }, { 0, NULL }, }; static const value_string rtcp_mcptt_loc_type_vals[] = { { 0x0, "Not provided" }, { 0x1, "ECGI" }, { 0x2, "Tracking Area" }, { 0x3, "PLMN ID" }, { 0x4, "MBMS Service Area" }, { 0x5, "MBSFN Area ID" }, { 0x6, "Geographic coordinates" }, { 0, NULL }, }; static int dissect_rtcp_mcptt_location_ie(tvbuff_t* tvb, packet_info* pinfo, int offset, proto_tree* tree, guint32 mcptt_fld_len) { guint32 loc_type; int start_offset = offset; static int * const ECGI_flags[] = { &hf_rtcp_mcptt_enodebid, &hf_rtcp_mcptt_cellid, NULL }; /* Location Type */ proto_tree_add_item_ret_uint(tree, hf_rtcp_mcptt_loc_type, tvb, offset, 1, ENC_BIG_ENDIAN, &loc_type); offset += 1; switch (loc_type) { case 0: /* Not provided */ break; case 1: /* ECGI - 56 bits = MCC + MNC + ECI*/ dissect_e212_mcc_mnc_wmem_packet_str(tvb, pinfo, tree, offset, E212_ECGI, TRUE); offset += 3; proto_tree_add_bitmask(tree, tvb, offset, hf_rtcp_mcptt_ecgi_eci, ett_rtcp_mcptt_eci, ECGI_flags, ENC_BIG_ENDIAN); offset += 4; break; case 2: /* Tracking Area - 40 bits = MCC + MNC + 16 bits */ /* ECGI - 56 bits = MCC + MNC + ECI*/ dissect_e212_mcc_mnc_wmem_packet_str(tvb, pinfo, tree, offset, E212_ECGI, TRUE); offset += 3; proto_tree_add_item(tree, hf_rtcp_mcptt_tac, tvb, offset, 2, ENC_NA); offset += 2; break; case 3: /* PLMN ID - 24 bits = MCC+MNC */ dissect_e212_mcc_mnc_wmem_packet_str(tvb, pinfo, tree, offset, E212_ECGI, TRUE); offset += 3; break; case 4: /* MBMS Service Area - 16 bits = [0-65535] */ proto_tree_add_item(tree, hf_rtcp_mcptt_mbms_serv_area, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; break; case 5: /* MBSFN Area ID - 8 bits = [0-255] */ proto_tree_add_item(tree, hf_rtcp_mcptt_mbsfn_area_id, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case 6: /* Geographic coordinates - 48 bits = latitude in first 24 bits + longitude in last 24 bits coded as * in subclause 6.1 in 3GPP TS 23.032 * XXX Make use of dissect_geographical_description() ? */ proto_tree_add_item(tree, hf_rtcp_mcptt_lat, tvb, offset, 3, ENC_BIG_ENDIAN); offset += 3; proto_tree_add_item(tree, hf_rtcp_mcptt_long, tvb, offset, 3, ENC_BIG_ENDIAN); offset += 3; break; default: proto_tree_add_expert(tree, pinfo, &ei_rtcp_mcptt_location_type, tvb, offset-1, 1); break; } if ((guint)(offset - start_offset) != mcptt_fld_len) { proto_tree_add_item(tree, hf_rtcp_app_data_padding, tvb, offset, offset - start_offset, ENC_BIG_ENDIAN); offset += (offset - start_offset); } return offset; } /* TS 24.380 */ static int dissect_rtcp_app_mcpt(tvbuff_t* tvb, packet_info* pinfo, int offset, proto_tree* tree, int packet_len, proto_item* subtype_item, guint rtcp_subtype) { proto_tree* sub_tree; guint32 mcptt_fld_id, mcptt_fld_len; col_add_fstr(pinfo->cinfo, COL_INFO, "(MCPT) %s", val_to_str(rtcp_subtype, rtcp_mcpt_subtype_vals, "unknown (%u)")); proto_item_append_text(subtype_item, " %s", val_to_str(rtcp_subtype, rtcp_mcpt_subtype_vals, "unknown (%u)")); sub_tree = proto_tree_add_subtree(tree, tvb, offset, packet_len, ett_rtcp_mcpt, NULL, "Mission Critical Push To Talk(MCPTT)"); offset += 4; packet_len -= 4; if (packet_len == 0) { return offset; } if (tvb_ascii_isprint(tvb, offset, packet_len - 3)) { proto_tree_add_item(tree, hf_rtcp_mcptt_str, tvb, offset, packet_len, ENC_ASCII | ENC_NA); proto_tree_add_expert(sub_tree, pinfo, &ei_rtcp_appl_non_conformant, tvb, offset, packet_len); return offset + packet_len; } while (packet_len > 0) { proto_item* ti; int len_len, padding = 0; int start_offset = offset; /* Field ID 8 bits*/ ti = proto_tree_add_item_ret_uint(sub_tree, hf_rtcp_mcptt_fld_id, tvb, offset, 1, ENC_BIG_ENDIAN, &mcptt_fld_id); offset++; /* Length value * a length value which is: * - one octet long, if the field ID is less than 192; and * - two octets long, if the field ID is equal to or greater than 192; */ if (mcptt_fld_id < 192) { len_len = 1; } else { len_len = 2; } proto_tree_add_item_ret_uint(sub_tree, hf_rtcp_mcptt_fld_len, tvb, offset, len_len, ENC_BIG_ENDIAN, &mcptt_fld_len); offset += len_len; if ((1 + len_len + mcptt_fld_len) % 4) { padding = (4 - ((1 + len_len + mcptt_fld_len) % 4)); } if (mcptt_fld_len != 0) { /* Field Value */ switch (mcptt_fld_id) { case 0: /* Floor Priority */ proto_tree_add_item(sub_tree, hf_rtcp_mcptt_priority, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; break; case 1: /* Duration */ proto_tree_add_item(sub_tree, hf_rtcp_mcptt_duration, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; break; case 2: { /* Reject Cause */ guint32 cause = 0; switch (rtcp_subtype) { case 3: /* Floor deny */ proto_tree_add_item_ret_uint(sub_tree, hf_rtcp_mcptt_rej_cause_floor_deny, tvb, offset, 2, ENC_BIG_ENDIAN, &cause); col_append_fstr(pinfo->cinfo, COL_INFO, " - %s", val_to_str_const(cause, rtcp_mcptt_rej_cause_floor_deny_vals, "Unknown")); break; case 6: /* Floor revoke */ proto_tree_add_item_ret_uint(sub_tree, hf_rtcp_mcptt_rej_cause_floor_revoke, tvb, offset, 2, ENC_BIG_ENDIAN, &cause); col_append_fstr(pinfo->cinfo, COL_INFO, " - %s", val_to_str_const(cause, rtcp_mcptt_rej_cause_floor_deny_vals, "Unknown")); break; default: proto_tree_add_item(sub_tree, hf_rtcp_mcptt_rej_cause, tvb, offset, 2, ENC_BIG_ENDIAN); break; } offset += 2; /* If the length field is set to '2', there is no value in the Reject Cause field */ if (mcptt_fld_len == 2) { break; } /* Reject Phrase */ proto_tree_add_item(sub_tree, hf_rtcp_mcptt_rej_phrase, tvb, offset, mcptt_fld_len - 2, ENC_UTF_8 | ENC_NA); offset += (mcptt_fld_len - 2); break; } case 3: /* Queue Info*/ proto_tree_add_item(sub_tree, hf_rtcp_mcptt_queue_pos_inf, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(sub_tree, hf_rtcp_mcptt_queue_pri_lev, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case 4: case 106: /* Granted Party's Identity */ proto_tree_add_item(sub_tree, hf_rtcp_mcptt_granted_partys_id, tvb, offset, mcptt_fld_len, ENC_UTF_8 | ENC_NA); offset += mcptt_fld_len; break; case 5: /* Permission to Request the Floor */ proto_tree_add_item(sub_tree, hf_rtcp_mcptt_perm_to_req_floor, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; break; case 6: /* User ID */ proto_tree_add_item(sub_tree, hf_rtcp_mcptt_user_id, tvb, offset, mcptt_fld_len, ENC_UTF_8 | ENC_NA); offset += mcptt_fld_len; break; case 7: /* Queue Size */ proto_tree_add_item(sub_tree, hf_rtcp_mcptt_queue_size, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; break; case 8: /* Message Sequence-Number */ proto_tree_add_item(sub_tree, hf_rtcp_mcptt_msg_seq_num, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; break; case 9: /* Queued User ID */ proto_tree_add_item(sub_tree, hf_rtcp_mcptt_queued_user_id, tvb, offset, mcptt_fld_len, ENC_UTF_8 | ENC_NA); offset += mcptt_fld_len; break; case 10: /* Source */ proto_tree_add_item(sub_tree, hf_rtcp_mcptt_source, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; break; case 11: { guint32 fld_len, num_ref; int rem_len = mcptt_fld_len; proto_tree* part_tree; /* Track Info */ proto_tree_add_item(sub_tree, hf_rtcp_mcptt_queueing_cap, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; rem_len -= 1; proto_tree_add_item_ret_uint(sub_tree, hf_rtcp_mcptt_part_type_len, tvb, offset, 1, ENC_BIG_ENDIAN, &fld_len); offset += 1; rem_len -= 1; int part_type_padding = (4 - (fld_len % 4)); proto_tree_add_item(sub_tree, hf_rtcp_mcptt_participant_type, tvb, offset, fld_len, ENC_UTF_8 | ENC_NA); offset += fld_len; rem_len -= fld_len; if(part_type_padding > 0){ guint32 data; proto_tree_add_item_ret_uint(sub_tree, hf_rtcp_app_data_padding, tvb, offset, part_type_padding, ENC_BIG_ENDIAN, &data); if (data != 0) { proto_tree_add_expert(sub_tree, pinfo, &ei_rtcp_appl_non_zero_pad, tvb, offset, part_type_padding); } offset += part_type_padding; rem_len -= part_type_padding; } if (rem_len > 0) { num_ref = 1; /* Floor Participant Reference */ while (rem_len > 0) { part_tree = proto_tree_add_subtree_format(sub_tree, tvb, offset, 4, ett_rtcp_mcptt_participant_ref, NULL, "Floor Participant Reference %u", num_ref); proto_tree_add_item(part_tree, hf_rtcp_mcptt_participant_ref, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; rem_len -= 4; num_ref++; } } break; } case 12: /* Message Type */ proto_tree_add_item(sub_tree, hf_rtcp_mcptt_msg_type, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item(sub_tree, hf_rtcp_spare16, tvb, offset, 1, ENC_NA); offset += 1; break; case 13: { /* Floor Indicator */ guint32 floor_ind; proto_tree_add_item_ret_uint(sub_tree, hf_rtcp_mcptt_floor_ind, tvb, offset, 2, ENC_BIG_ENDIAN, &floor_ind); col_append_fstr(pinfo->cinfo, COL_INFO, " - %s", val_to_str_const(floor_ind, mcptt_floor_ind_vals, "Unknown")); offset += 2; break; } case 14: /* SSRC */ proto_tree_add_item(sub_tree, hf_rtcp_mcptt_ssrc, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(sub_tree, hf_rtcp_spare16, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; break; case 15: /* List of Granted Users */ { guint32 num_users, user_id_len; /* No of users */ proto_tree_add_item_ret_uint(sub_tree, hf_rtcp_mcptt_num_users, tvb, offset, 1, ENC_BIG_ENDIAN, &num_users); offset += 1; while (num_users > 0) { proto_tree_add_item_ret_uint(sub_tree, hf_rtcp_mcptt_user_id_len, tvb, offset, 1, ENC_BIG_ENDIAN, &user_id_len); offset += 1; proto_tree_add_item(sub_tree, hf_rtcp_mcptt_user_id, tvb, offset, user_id_len, ENC_UTF_8 | ENC_NA); offset += user_id_len; num_users--; } break; } case 16: /* List of SSRCs */ { guint32 num_ssrc; /* Number of SSRCs*/ proto_tree_add_item_ret_uint(sub_tree, hf_rtcp_mcptt_num_ssrc, tvb, offset, 1, ENC_BIG_ENDIAN, &num_ssrc); offset += 1; proto_tree_add_item(sub_tree, hf_rtcp_spare16, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; while (num_ssrc > 0) { proto_tree_add_item(sub_tree, hf_rtcp_mcptt_ssrc, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; num_ssrc--; } break; } case 17: /* Functional Alias */ proto_tree_add_item(sub_tree, hf_rtcp_mcptt_func_alias, tvb, offset, mcptt_fld_len, ENC_UTF_8 | ENC_NA); offset += mcptt_fld_len; break; case 18: /* List of Functional Aliases */ { guint32 num_fas, fa_len; /* No of FAs */ proto_tree_add_item_ret_uint(sub_tree, hf_rtcp_mcptt_num_fas, tvb, offset, 1, ENC_BIG_ENDIAN, &num_fas); offset += 1; while (num_fas > 0) { proto_tree_add_item_ret_uint(sub_tree, hf_rtcp_mcptt_fa_len, tvb, offset, 1, ENC_BIG_ENDIAN, &fa_len); offset += 1; proto_tree_add_item(sub_tree, hf_rtcp_mcptt_func_alias, tvb, offset, fa_len, ENC_UTF_8 | ENC_NA); offset += fa_len; num_fas--; } break; } case 19: /* Location */ offset = dissect_rtcp_mcptt_location_ie(tvb, pinfo, offset, sub_tree, mcptt_fld_len); break; case 20: /* List of Locations */ { guint32 num_loc; /* Number of SSRCs*/ proto_tree_add_item_ret_uint(sub_tree, hf_rtcp_mcptt_num_loc, tvb, offset, 1, ENC_BIG_ENDIAN, &num_loc); offset += 1; while (num_loc > 0) { offset = dissect_rtcp_mcptt_location_ie(tvb, pinfo, offset, sub_tree, mcptt_fld_len); num_loc--; } break; } default: expert_add_info(pinfo, ti, &ei_rtcp_mcptt_unknown_fld); proto_tree_add_item(sub_tree, hf_rtcp_mcptt_fld_val, tvb, offset, mcptt_fld_len, ENC_NA); offset += mcptt_fld_len; break; } } if (padding) { guint32 data; proto_tree_add_item_ret_uint(sub_tree, hf_rtcp_app_data_padding, tvb, offset, padding, ENC_BIG_ENDIAN, &data); if (data != 0) { proto_tree_add_expert(sub_tree, pinfo, &ei_rtcp_appl_non_zero_pad, tvb, offset, padding); } offset += padding; } packet_len -= offset - start_offset; if (packet_len >= 4) { guint32 dword = tvb_get_ntohl(tvb, offset); if (dword == 0) { /* Extra 4 zero bytes */ proto_tree_add_expert(sub_tree, pinfo, &ei_rtcp_appl_extra_bytes, tvb, offset, 4); packet_len -= 4; offset += 4; } } } return offset; } /* TS 24.380 V 13.2.0*/ static int dissect_rtcp_app_mccp(tvbuff_t* tvb, packet_info* pinfo, int offset, proto_tree* tree, int packet_len, proto_item* subtype_item, guint rtcp_subtype) { proto_tree* sub_tree; guint32 mccp_fld_id, mccp_fld_len; int total_packet_length; col_add_fstr(pinfo->cinfo, COL_INFO, "(MCCP) %s", val_to_str(rtcp_subtype, rtcp_mccp_subtype_vals, "unknown (%u)")); proto_item_append_text(subtype_item, " %s", val_to_str(rtcp_subtype, rtcp_mccp_subtype_vals, "unknown (%u)")); if (packet_len <= 0) { total_packet_length = tvb_reported_length_remaining(tvb, offset); proto_tree_add_expert_format(tree, pinfo, &ei_rtcp_length_check, tvb, offset, total_packet_length, "Incorrect RTCP packet length information (expected 0 bytes, found %d)", total_packet_length); packet_len = total_packet_length; } sub_tree = proto_tree_add_subtree(tree, tvb, offset, packet_len, ett_rtcp_mcpt, NULL, "MBMS subchannel control"); offset += 4; packet_len -= 4; if (packet_len == 0) { return offset; } while (packet_len > 0) { proto_item* ti; int padding = 0; int start_offset = offset; /* Each MBMS subchannel control specific field consists of an 8-bit item, * an 8-bit octet value item containing the length of the field value not * including or the value items. */ ti = proto_tree_add_item_ret_uint(sub_tree, hf_rtcp_mccp_field_id, tvb, offset, 1, ENC_BIG_ENDIAN, &mccp_fld_id); offset += 1; packet_len -= 1; proto_tree_add_item_ret_uint(sub_tree, hf_rtcp_mccp_len, tvb, offset, 1, ENC_BIG_ENDIAN, &mccp_fld_len); offset += 1; packet_len -= 1; if ((2 + mccp_fld_len) % 4) { padding = (4 - ((2 + mccp_fld_len) % 4)); } switch (mccp_fld_id) { case 0: { /* Subchannel */ /*The