From a584eab239d55e441433ead40c993e08a24c59fe Mon Sep 17 00:00:00 2001 From: ZHANG Rui Date: Thu, 18 Jan 2018 17:45:49 +0800 Subject: New RTCP dissector for transport-cc Bug: 14332 Change-Id: I49642a9880fc03d38942eebfd6b1015894fef23d Reviewed-on: https://code.wireshark.org/review/25255 Reviewed-by: Michael Mann Petri-Dish: Michael Mann Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman --- epan/dissectors/packet-rtcp.c | 361 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 359 insertions(+), 2 deletions(-) (limited to 'epan/dissectors/packet-rtcp.c') diff --git a/epan/dissectors/packet-rtcp.c b/epan/dissectors/packet-rtcp.c index cacad6f12c..b7e42a0e1a 100644 --- a/epan/dissectors/packet-rtcp.c +++ b/epan/dissectors/packet-rtcp.c @@ -359,6 +359,7 @@ 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 } }; @@ -546,6 +547,14 @@ 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; @@ -1111,6 +1120,255 @@ dissect_rtcp_psfb_remb( tvbuff_t *tvb, int offset, proto_tree *rtcp_tree, proto_ return offset; } +#define RTCP_HEADER_LENGTH 12 + +static int +dissect_rtcp_rtpfb_transport_cc( tvbuff_t *tvb, int offset, proto_tree *rtcp_tree, 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; + gint fci_length = pkt_len - RTCP_HEADER_LENGTH; + int delta_index = 0; + 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( wmem_packet_scope(), gint8, pkt_count ); + pkt_seq_array = wmem_alloc0_array( wmem_packet_scope(), 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 */ + int length = chunk & 0x1FFF; + + if ( length <= 0 ) + { + /*Malfromed Packet, stop parse it*/ + delta_array = NULL; + pkt_seq_array = NULL; + + 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 (int 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 (int 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(wmem_packet_scope(), "|"); + + /* 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 + { + 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*/ + 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*/ + 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; + } + + /* delta_array / pkt_seq_array will be freed out of wmem_packet_scope*/ + 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) { @@ -1203,6 +1461,9 @@ dissect_rtcp_rtpfb( tvbuff_t *tvb, int offset, proto_tree *rtcp_tree, proto_item 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, rtcp_tree, packet_length); } else { /* Unknown FMT */ proto_tree_add_item(rtcp_tree, hf_rtcp_fci, tvb, offset, start_offset + packet_length - offset, ENC_NA ); @@ -3573,7 +3834,7 @@ dissect_rtcp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U /* offset should be total_packet_length by now... */ else if (offset == total_packet_length) { - ti = proto_tree_add_boolean_format_value(tree, hf_rtcp_length_check, tvb, + ti = proto_tree_add_boolean_format_value(rtcp_tree, hf_rtcp_length_check, tvb, 0, 0, TRUE, "OK - %u bytes", offset); /* Hidden might be less annoying here...? */ @@ -3581,7 +3842,7 @@ dissect_rtcp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U } else { - ti = proto_tree_add_boolean_format_value(tree, hf_rtcp_length_check, tvb, + ti = proto_tree_add_boolean_format_value(rtcp_tree, hf_rtcp_length_check, tvb, 0, 0, FALSE, "Wrong (expected %u bytes, found %d)", total_packet_length, offset); @@ -5507,6 +5768,102 @@ proto_register_rtcp(void) NULL, HFILL } }, + { + &hf_rtcp_rtpfb_transport_cc_fci_base_seq, + { + "Base Sequence Number", + "rtcp.rtpfb.transportcc.baseseq", + FT_UINT16, + BASE_DEC_HEX, + NULL, + 0x0, + NULL, HFILL + } + }, + { + &hf_rtcp_rtpfb_transport_cc_fci_pkt_stats_cnt, + { + "Packet Status Count", + "rtcp.rtpfb.transportcc.statuscount", + FT_UINT16, + BASE_DEC_HEX, + NULL, + 0x0, + NULL, HFILL + } + }, + { + &hf_rtcp_rtpfb_transport_cc_fci_ref_time, + { + "Reference Time", + "rtcp.rtpfb.transportcc.reftime", + FT_UINT24, + BASE_DEC_HEX, + NULL, + 0x0, + NULL, HFILL + } + }, + { + &hf_rtcp_rtpfb_transport_cc_fci_fb_pkt_cnt, + { + "Feedback Packets Count", + "rtcp.rtpfb.transportcc.pktcount", + FT_UINT8, + BASE_DEC_HEX, + NULL, + 0x0, + NULL, HFILL + } + }, + { + &hf_rtcp_rtpfb_transport_cc_fci_pkt_chunk, + { + "Packet Chunk", + "rtcp.rtpfb.transportcc.pktchunk", + FT_UINT16, + BASE_DEC_HEX, + NULL, + 0x0, + NULL, HFILL + } + }, + { + &hf_rtcp_rtpfb_transport_cc_fci_recv_delta_1_byte, + { + "Recv Delta", + "rtcp.rtpfb.transportcc.recv_delta", + FT_UINT8, + BASE_HEX, + NULL, + 0x0, + NULL, HFILL + } + }, + { + &hf_rtcp_rtpfb_transport_cc_fci_recv_delta_2_bytes, + { + "Recv Delta", + "rtcp.rtpfb.transportcc.recv_delta", + FT_UINT16, + BASE_HEX, + NULL, + 0x0, + NULL, HFILL + } + }, + { + &hf_rtcp_rtpfb_transport_cc_fci_recv_delta_padding, + { + "Recv Delta Padding", + "rtcp.rtpfb.transportcc.recv_delta.padding", + FT_UINT16, + BASE_HEX, + NULL, + 0x0, + NULL, HFILL + } + }, { -- cgit v1.2.3