#if 0 out the stuff to set the reported length, as it'd throw an
[obnox/wireshark/wip.git] / packet-rtcp.c
index aaff7c7b64f4e870037a14cfcde920c3c4e64448..2274dd8bc2168384c93a583172a5cc05eecb6dca 100644 (file)
 /* packet-rtcp.c
- * Routines for RTCP packet disassembly
  *
- * Jason Lango <jal@netapp.com>
+ * $Id: packet-rtcp.c,v 1.37 2003/05/28 22:40:19 guy Exp $
  *
- * $Id: packet-rtcp.c,v 1.1 2000/04/21 01:45:56 guy Exp $
+ * Routines for RTCP dissection
+ * RTCP = Real-time Transport Control Protocol
+ *
+ * Copyright 2000, Philips Electronics N.V.
+ * Written by Andreas Sikkema <andreas.sikkema@philips.com>
  *
  * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
+ * By Gerald Combs <gerald@ethereal.com>
  * Copyright 1998 Gerald Combs
  *
- * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
  * of the License, or (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/*
+ * This dissector tries to dissect the RTCP protocol according to Annex A
+ * of ITU-T Recommendation H.225.0 (02/98) and RFC 1889
+ * H.225.0 literally copies RFC 1889, but omitting a few sections.
  *
+ * RTCP traffic is 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
  *
  */
 
-#include "config.h"
 
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
+#ifdef HAVE_CONFIG_H
+# include "config.h"
 #endif
 
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
+#include <glib.h>
+#include <epan/packet.h>
 
+#include <stdio.h>
 #include <string.h>
-#include <ctype.h>
 
-#include <glib.h>
-#include "packet.h"
 #include "packet-rtcp.h"
+#if 0
+#include "packet-ntp.h"
+#endif
+#include <epan/conversation.h>
 
-static int proto_rtcp = -1;
-
-static gint ett_rtcp = -1;
-
-#define _RTCP_FLAG_BITS(hdr, s, n) \
-       ((u_int)(((hdr)->rtcp_flag_bits >> (8 - (s) - (n))) & ((1 << (n)) - 1)))
-#define RTCP_VERSION(hdr)      _RTCP_FLAG_BITS(hdr, 0, 2)
-#define RTCP_PADDING(hdr)      _RTCP_FLAG_BITS(hdr, 2, 1)
-#define RTCP_COUNT(hdr)                _RTCP_FLAG_BITS(hdr, 3, 5)
-
-#define RTCP_TYPE_SR           200     /* Sender Report */
-#define RTCP_TYPE_RR           201     /* Receiver Report */
-#define RTCP_TYPE_SDES         202     /* Source Description */
-#define RTCP_TYPE_BYE          203     /* Goodbye */
-#define RTCP_TYPE_APP          204     /* Application-defined */
-
-typedef struct rtcp_hdr {
-       guint8  rtcp_flag_bits;
-       guint8  rtcp_type;              /* packet type */
-       guint16 rtcp_length;            /* length in 32 bit words minus 1 */
-} rtcp_hdr_t;
-
-typedef struct rtcp_report {
-       guint32 rtcp_rr_ssrc;           /* SSRC of source */
-       guint8  rtcp_rr_flt;            /* fraction lost */
-       guint8  rtcp_rr_cplthi;         /* hi-byte of cplt */
-       guint16 rtcp_rr_cplt;           /* cumulative packets lost */
-       guint32 rtcp_rr_xhiseq;         /* extended highest seq num rcvd */
-       guint32 rtcp_rr_jitter;         /* interarrival jitter */
-       guint32 rtcp_rr_lsr;            /* middle bits of last SR timestamp */
-       guint32 rtcp_rr_dlsr;           /* delay since last SR */
-} rtcp_report_t;
+/* Version is the first 2 bits of the first octet*/
+#define RTCP_VERSION(octet)    ((octet) >> 6)
 
-static int
-dissect_rtcp_report(rtcp_hdr_t *hdr, int sn, const u_char *pd, int offset,
-       int start_packet, int end_packet, proto_tree *rtcp_tree)
+/* 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 const value_string rtcp_version_vals[] =
 {
-       int             end_offset = offset + END_OF_FRAME;
-       rtcp_report_t   rep;
-
-       if (offset >= end_offset)
-               return -1;
-
-       memcpy(&rep, &pd[offset], sizeof(rtcp_report_t) <= END_OF_FRAME ?
-               sizeof(rtcp_report_t) : END_OF_FRAME);
-
-       rep.rtcp_rr_ssrc = ntohl(rep.rtcp_rr_ssrc);
-       rep.rtcp_rr_cplt = ntohs(rep.rtcp_rr_cplt);
-       rep.rtcp_rr_xhiseq = ntohl(rep.rtcp_rr_xhiseq);
-       rep.rtcp_rr_jitter = ntohl(rep.rtcp_rr_jitter);
-       rep.rtcp_rr_lsr = ntohl(rep.rtcp_rr_lsr);
-       rep.rtcp_rr_dlsr = ntohl(rep.rtcp_rr_dlsr);
-
-       if ((offset + sizeof(rtcp_report_t)) > end_offset) {
-               proto_tree_add_text(rtcp_tree, offset, 0,
-                       "Warning: Bad packet length -- "
-                       "data might be incorrect");
-       }
+       { 0, "Old VAT Version" },
+       { 1, "First Draft Version" },
+       { 2, "RFC 1889 Version" },
+       { 0, NULL },
+};
 
-       proto_tree_add_text(rtcp_tree, offset, 4,
-               "Source %d SSRC: %u", sn + 1, rep.rtcp_rr_ssrc);
-       offset += 4;
+/* RTCP packet types according to Section A.11.1 */
+#define RTCP_SR   200
+#define RTCP_RR   201
+#define RTCP_SDES 202
+#define RTCP_BYE  203
+#define RTCP_APP  204
+/* Supplemental H.261 specific RTCP packet types according to Section C.3.5 */
+#define RTCP_FIR  192
+#define RTCP_NACK 193
+
+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_FIR,  "Full Intra-frame Request (H.261)" },
+       { RTCP_NACK, "Negative Acknowledgement (H.261)" },
+       { 0,         NULL },
+};
 
-       proto_tree_add_text(rtcp_tree, offset, 1,
-               "Fraction lost: %u / 256", (unsigned) rep.rtcp_rr_flt);
-       offset += 1;
+/* 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
+
+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)" },
+       { 0,               NULL },
+};
 
-       proto_tree_add_text(rtcp_tree, offset, 3,
-               "Cumulative Packets Lost: %lu",
-               (((unsigned long) rep.rtcp_rr_cplthi) << 16) +
-               (unsigned long) rep.rtcp_rr_cplt);
-       offset += 3;
+/* RTCP header fields                   */
+static int proto_rtcp                = -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_ntp               = -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;
+/* 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_ssrc_type         = -1;
+static int hf_rtcp_ssrc_length       = -1;
+static int hf_rtcp_ssrc_text         = -1;
+static int hf_rtcp_ssrc_prefix_len   = -1;
+static int hf_rtcp_ssrc_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_fsn               = -1;
+static int hf_rtcp_blp               = -1;
+static int hf_rtcp_padding_count     = -1;
+static int hf_rtcp_padding_data      = -1;
+
+/* RTCP fields defining a sub tree */
+static gint ett_rtcp           = -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 address fake_addr;
+static int heur_init = FALSE;
+
+static gboolean dissect_rtcp_heur( tvbuff_t *tvb, packet_info *pinfo,
+    proto_tree *tree );
+static void dissect_rtcp( tvbuff_t *tvb, packet_info *pinfo,
+     proto_tree *tree );
+
+void rtcp_add_address( packet_info *pinfo, const unsigned char* ip_addr,
+    int prt )
+{
+       address src_addr;
+       conversation_t* pconv;
 
-       proto_tree_add_text(rtcp_tree, offset, 4,
-               "Extended Highest Seq #: %lu",
-               (unsigned long) rep.rtcp_rr_xhiseq);
-       offset += 4;
+       /*
+        * If this isn't the first time this packet has been processed,
+        * we've already done this work, so we don't need to do it
+        * again.
+        */
+       if (pinfo->fd->flags.visited)
+               return;
 
-       proto_tree_add_text(rtcp_tree, offset, 4,
-               "Jitter: %lu", (unsigned long) rep.rtcp_rr_jitter);
-       offset += 4;
+       src_addr.type = AT_IPv4;
+       src_addr.len = 4;
+       src_addr.data = ip_addr;
 
-       proto_tree_add_text(rtcp_tree, offset, 4,
-               "Last SR timestamp (middle): %lu",
-               (unsigned long) rep.rtcp_rr_lsr);
-       offset += 4;
+       /*
+        * The first time the function is called let the udp dissector
+        * know that we're interested in traffic
+        */
+       if ( ! heur_init ) {
+               heur_dissector_add( "udp", dissect_rtcp_heur, proto_rtcp );
+               heur_init = TRUE;
+       }
 
-       proto_tree_add_text(rtcp_tree, offset, 4,
-               "Delay Since Last SR: %lu",
-               (unsigned long) rep.rtcp_rr_dlsr);
-       offset += 4;
+       /*
+        * Check if the ip address and port combination is not
+        * already registered
+        */
+       pconv = find_conversation( &src_addr, &fake_addr, PT_UDP, prt, 0, 0 );
+
+       /*
+        * If not, add
+        * XXX - use wildcard address and port B?
+        */
+       if ( ! pconv ) {
+               pconv = conversation_new( &src_addr, &fake_addr, PT_UDP,
+                   (guint32) prt, (guint32) 0, 0 );
+               conversation_add_proto_data(pconv, proto_rtcp, NULL);
+       }
 
-       return offset;
 }
 
-typedef struct rtcp_rr {
-       guint32 rtcp_rr_ssrc;
-} rtcp_rr_t;
+#if 0
+static void rtcp_init( void )
+{
+       unsigned char* tmp_data;
+       int i;
 
-static int
-dissect_rtcp_rr(rtcp_hdr_t *hdr, const u_char *pd, int offset,
-       int start_packet, int end_packet, proto_tree *rtcp_tree)
+       /* Create a fake adddress... */
+       fake_addr.type = AT_IPv4;
+       fake_addr.len = 4;
+
+       tmp_data = g_malloc( fake_addr.len );
+       for ( i = 0; i < fake_addr.len; i++) {
+               tmp_data[i] = 0;
+       }
+       fake_addr.data = tmp_data;
+}
+#endif
+
+static gboolean
+dissect_rtcp_heur( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
 {
-       int             end_offset = offset + END_OF_FRAME; 
-       rtcp_rr_t       rr;
-       int             sn;
-
-       memcpy(&rr, &pd[offset], sizeof(rtcp_rr_t) < END_OF_FRAME ?
-               sizeof(rtcp_rr_t) : END_OF_FRAME);
-       rr.rtcp_rr_ssrc = ntohl(rr.rtcp_rr_ssrc);
-
-       if ((offset + sizeof(rtcp_rr_t)) >= end_offset)
-               return -1;
-       proto_tree_add_text(rtcp_tree, offset, 4, "Sender SSRC: %u",
-               rr.rtcp_rr_ssrc);
-       offset += 4;
+       conversation_t* pconv;
 
-       for (sn = 0; sn < RTCP_COUNT(hdr); sn++) {
-               offset = dissect_rtcp_report(hdr, sn, pd, offset, start_packet,
-                       end_packet, rtcp_tree);
+       /* This is a heuristic dissector, which means we get all the UDP
+        * traffic not sent to a known dissector and not claimed by
+        * a heuristic dissector called before us!
+        * So we first check if the frame is really meant for us.
+        */
+       if ( ( pconv = find_conversation( &pinfo->src, &fake_addr, pinfo->ptype,
+           pinfo->srcport, 0, 0 ) ) == NULL ) {
+               /*
+                * The source ip:port combination was not what we were
+                * looking for, check the destination
+                */
+               if ( ( pconv = find_conversation( &pinfo->dst, &fake_addr,
+                   pinfo->ptype, pinfo->destport, 0, 0 ) ) == NULL ) {
+                       return FALSE;
+               }
        }
 
-       return offset;
+
+       /*
+        * An RTCP conversation always has a data item for RTCP.
+        * (Its existence is sufficient to indicate that this is an RTCP
+        * conversation.)
+        */
+       if (conversation_get_proto_data(pconv, proto_rtcp) == NULL)
+               return FALSE;
+
+       /*
+        * The message is a valid RTCP message!
+        */
+       dissect_rtcp( tvb, pinfo, tree );
+
+       return TRUE;
 }
 
-typedef struct rtcp_sr {
-       guint32 rtcp_sr_ssrc;
-       guint32 rtcp_sr_ntp_hi;         /* MSW of NTP timestamp */
-       guint32 rtcp_sr_ntp_lo;         /* LSW of NTP timestamp */
-       guint32 rtcp_sr_rtp_time;       /* RTP timestamp */
-       guint32 rtcp_sr_npackets;       /* sender's packet count */
-       guint32 rtcp_sr_nbytes;         /* sender's octet count */
-} rtcp_sr_t;
 
 static int
-dissect_rtcp_sr(rtcp_hdr_t *hdr, const u_char *pd, int offset,
-       int start_packet, int end_packet, proto_tree *rtcp_tree)
+dissect_rtcp_nack( tvbuff_t *tvb, int offset, proto_tree *tree )
 {
-       int             end_offset = offset + END_OF_FRAME; 
-       rtcp_sr_t       sr;
-       int             sn;
-
-       memcpy(&sr, &pd[offset], sizeof(rtcp_sr_t) < END_OF_FRAME ?
-               sizeof(rtcp_sr_t) : END_OF_FRAME);
-       sr.rtcp_sr_ssrc = ntohl(sr.rtcp_sr_ssrc);
-       sr.rtcp_sr_ntp_hi = ntohl(sr.rtcp_sr_ntp_hi);
-       sr.rtcp_sr_ntp_lo = ntohl(sr.rtcp_sr_ntp_lo);
-       sr.rtcp_sr_rtp_time = ntohl(sr.rtcp_sr_rtp_time);
-       sr.rtcp_sr_npackets = ntohl(sr.rtcp_sr_npackets);
-       sr.rtcp_sr_nbytes = ntohl(sr.rtcp_sr_nbytes);
-
-       if ((offset + sizeof(rtcp_sr_t)) > end_offset) {
-               proto_tree_add_text(rtcp_tree, offset, 0,
-                       "Warning: Bad packet length -- "
-                       "data might be incorrect");
-       }
+       /* Packet type = FIR (H261) */
+       proto_tree_add_uint( tree, hf_rtcp_rc, tvb, offset, 1, tvb_get_guint8( tvb, offset ) & 31 );
+       offset++;
+       /* Packet type, 8 bits  = APP */
+       proto_tree_add_item( tree, hf_rtcp_pt, tvb, offset, 1, FALSE );
+       offset++;
 
-       proto_tree_add_text(rtcp_tree, offset, 4, "Sender's SSRC: %u",
-               sr.rtcp_sr_ssrc);
-       offset += 4;
-       proto_tree_add_text(rtcp_tree, offset, 4, "NTP timestamp, MSW: %u",
-               sr.rtcp_sr_ntp_hi);
-       offset += 4;
-       proto_tree_add_text(rtcp_tree, offset, 4, "NTP timestamp, LSW: %u",
-               sr.rtcp_sr_ntp_lo);
-       offset += 4;
-       proto_tree_add_text(rtcp_tree, offset, 4, "RTP timestamp: %u",
-               sr.rtcp_sr_rtp_time);
-       offset += 4;
-       proto_tree_add_text(rtcp_tree, offset, 4, "Sender's packet count: %u",
-               sr.rtcp_sr_npackets);
-       offset += 4;
-       proto_tree_add_text(rtcp_tree, offset, 4, "Sender's octet count: %u",
-               sr.rtcp_sr_nbytes);
+       /* Packet length in 32 bit words minus one */
+       proto_tree_add_uint( tree, hf_rtcp_length, tvb, offset, 2, tvb_get_ntohs( tvb, offset ) );
+       offset += 2;
+
+       /* SSRC  */
+       proto_tree_add_uint( tree, hf_rtcp_ssrc_source, tvb, offset, 4, tvb_get_ntohl( tvb, offset ) );
        offset += 4;
 
-       for (sn = 0; sn < RTCP_COUNT(hdr); sn++) {
-               offset = dissect_rtcp_report(hdr, sn, pd, offset, start_packet,
-                       end_packet, rtcp_tree);
-       }
+       /* FSN, 16 bits */
+       proto_tree_add_uint( tree, hf_rtcp_fsn, tvb, offset, 2, tvb_get_ntohs( tvb, offset ) );
+       offset += 2;
+
+       /* BLP, 16 bits */
+       proto_tree_add_uint( tree, hf_rtcp_blp, tvb, offset, 2, tvb_get_ntohs( tvb, offset ) );
+       offset += 2;
 
        return offset;
 }
 
-static struct rtcp_chunk_type {
-       int             type;
-       const char      *name;
-} rtcp_chunk_types[] = {
-       { 1, "CNAME (user and domain)" },
-       { 2, "NAME (common name)" },
-       { 3, "EMAIL (e-mail address)" },
-       { 4, "PHONE (phone number)" },
-       { 5, "LOC (geographic location)" },
-       { 6, "TOOL (name/version of source app)" },
-       { 7, "NOTE (note about source)" },
-       { 8, "PRIV (private extensions)" },
-       { 0, 0 }
-};
+static int
+dissect_rtcp_fir( tvbuff_t *tvb, int offset, proto_tree *tree )
+{
+       /* Packet type = FIR (H261) */
+       proto_tree_add_uint( tree, hf_rtcp_rc, tvb, offset, 1, tvb_get_guint8( tvb, offset ) & 31 );
+       offset++;
+       /* Packet type, 8 bits  = APP */
+       proto_tree_add_item( tree, hf_rtcp_pt, tvb, offset, 1, FALSE );
+       offset++;
+
+       /* Packet length in 32 bit words minus one */
+       proto_tree_add_uint( tree, hf_rtcp_length, tvb, offset, 2, tvb_get_ntohs( tvb, offset ) );
+       offset += 2;
+
+       /* SSRC  */
+       proto_tree_add_uint( tree, hf_rtcp_ssrc_source, tvb, offset, 4, tvb_get_ntohl( tvb, offset ) );
+       offset += 4;
+
+       return offset;
+}
 
-static struct rtcp_chunk_type *
-rtcp_find_chunk_type(int type)
+static int
+dissect_rtcp_app( tvbuff_t *tvb, int offset, proto_tree *tree,
+    unsigned int padding, unsigned int packet_len )
 {
-       struct rtcp_chunk_type *tt = rtcp_chunk_types;
-       static struct rtcp_chunk_type unk = { 0, "UNKNOWN" };
-       for (; tt->type; tt++) {
-               if (type == tt->type)
-                       return tt;
+       unsigned int counter = 0;
+       char ascii_name[5];
+
+       /* SSRC / CSRC */
+       proto_tree_add_uint( tree, hf_rtcp_ssrc_source, tvb, offset, 4, tvb_get_ntohl( tvb, offset ) );
+       offset += 4;
+       packet_len -= 4;
+
+       /* Name (ASCII) */
+       for( counter = 0; counter < 4; counter++ )
+           ascii_name[ counter ] = tvb_get_guint8( tvb, offset + counter );
+       /* strncpy( ascii_name, pd + offset, 4 ); */
+       ascii_name[4] = '\0';
+       proto_tree_add_string( tree, hf_rtcp_name_ascii, tvb, offset, 4,
+           ascii_name );
+       offset += 4;
+       packet_len -= 4;
+
+       /* Applications specific data */
+       if ( padding ) {
+               /* If there's padding present, we have to remove that from the data part
+                * The last octet of the packet contains the length of the padding
+                */
+               packet_len -= tvb_get_guint8( tvb, offset + packet_len - 1 );
        }
-       return &unk;
+       proto_tree_add_item( tree, hf_rtcp_app_data, tvb, offset, packet_len, FALSE );
+       offset += packet_len;
+
+       return offset;
 }
 
 static int
-dissect_rtcp_sdes_chunk(rtcp_hdr_t *hdr, int cn, const u_char *pd, int offset,
-       int start_packet, int end_packet, proto_tree *rtcp_tree)
+dissect_rtcp_bye( tvbuff_t *tvb, int offset, proto_tree *tree,
+    unsigned int count )
 {
-       unsigned        type;
-       unsigned        len;
-       struct rtcp_chunk_type *ctype;
-
-       if ((offset + 4) > end_packet)
-               return -1;
-       proto_tree_add_text(rtcp_tree, offset, 4, "Chunk %d SSRC: %u",
-               cn + 1, pntohl(&pd[offset]));
-       offset += 4;
+       unsigned int chunk          = 1;
+       unsigned int reason_length  = 0;
+       unsigned int counter = 0;
+       char* reason_text = NULL;
+
+       while ( chunk <= count ) {
+               /* source identifier, 32 bits */
+               proto_tree_add_item( tree, hf_rtcp_ssrc_source, tvb, offset, 4, FALSE);
+               offset += 4;
+               chunk++;
+       }
 
-       for (;;) {
-               if ((offset + 1) > end_packet)
-                       return -1;
+       if ( tvb_reported_length_remaining( tvb, offset ) > 0 ) {
+               /* Bye reason consists of an 8 bit length l and a string with length l */
+               reason_length = tvb_get_guint8( tvb, offset );
+               proto_tree_add_item( tree, hf_rtcp_ssrc_length, tvb, offset, 1, FALSE );
+               offset++;
 
-               type = pd[offset];
-               if (type == 0) {
-                       int pad_start = offset;
+               reason_text = g_malloc( reason_length + 1 );
+               for ( counter = 0; counter < reason_length; counter++ ) reason_text[ counter ] = tvb_get_guint8( tvb, offset + counter );
+               /* strncpy( reason_text, pd + offset, reason_length ); */
+               reason_text[ reason_length ] = '\0';
+               proto_tree_add_string( tree, hf_rtcp_ssrc_text, tvb, offset, reason_length, reason_text );
+               g_free( reason_text );
+               offset += reason_length;
+       }
+
+       return offset;
+
+}
+
+static void
+dissect_rtcp_sdes( tvbuff_t *tvb, int offset, proto_tree *tree,
+    unsigned int count )
+{
+       unsigned int chunk          = 1;
+       proto_item *sdes_item;
+       proto_tree *sdes_tree;
+       proto_tree *sdes_item_tree;
+       proto_item *ti;
+       int start_offset;
+       int items_start_offset;
+       guint32 ssrc;
+       unsigned int item_len       = 0;
+       unsigned int sdes_type      = 0;
+       unsigned int counter        = 0;
+       unsigned int prefix_len     = 0;
+       char *prefix_string = NULL;
+
+       while ( chunk <= count ) {
+               /* Create a subtree for this chunk; we don't yet know
+                  the length. */
+               start_offset = offset;
+
+               ssrc = tvb_get_ntohl( tvb, offset );
+               sdes_item = proto_tree_add_text(tree, tvb, offset, -1,
+                   "Chunk %u, SSRC/CSRC %u", chunk, ssrc);
+               sdes_tree = proto_item_add_subtree( sdes_item, ett_sdes );
+
+               /* SSRC_n source identifier, 32 bits */
+               proto_tree_add_uint( sdes_tree, hf_rtcp_ssrc_source, tvb, offset, 4, ssrc );
+               offset += 4;
+
+               /* Create a subtree for the SDES items; we don't yet know
+                  the length */
+               items_start_offset = offset;
+               ti = proto_tree_add_text(sdes_tree, tvb, offset, -1,
+                   "SDES items" );
+               sdes_item_tree = proto_item_add_subtree( ti, ett_sdes_item );
+
+               /*
+                * Not every message is ended with "null" bytes, so check for
+                * end of frame instead.
+                */
+               while ( ( tvb_reported_length_remaining( tvb, offset ) > 0 )
+                   && ( tvb_get_guint8( tvb, offset ) != RTCP_SDES_END ) ) {
+                       /* ID, 8 bits */
+                       sdes_type = tvb_get_guint8( tvb, offset );
+                       proto_tree_add_item( sdes_item_tree, hf_rtcp_ssrc_type, tvb, offset, 1, FALSE );
                        offset++;
-                       /* NULL terminator -- align to next 32 bit boundary */
-                       if ((offset - start_packet) & 3) {
-                               offset += 4 - ((offset - start_packet) & 3);
-                       }
-                       proto_tree_add_text(rtcp_tree, pad_start,
-                               offset - pad_start,
-                               "(end of chunk and alignment padding)");
-                       break;
-               }
 
-               ctype = rtcp_find_chunk_type(type);
+                       /* Item length, 8 bits */
+                       item_len = tvb_get_guint8( tvb, offset );
+                       proto_tree_add_item( sdes_item_tree, hf_rtcp_ssrc_length, tvb, offset, 1, FALSE );
+                       offset++;
 
-               proto_tree_add_text(rtcp_tree, offset, 1, "Chunk type: %s",
-                       ctype->name);
-               offset++;
+                       if ( sdes_type == RTCP_SDES_PRIV ) {
+                               /* PRIV adds two items between the SDES length
+                                * and value - an 8 bit length giving the
+                                * length of a "prefix string", and the string.
+                                */
+                               prefix_len = tvb_get_guint8( tvb, offset );
+                               proto_tree_add_item( sdes_item_tree, hf_rtcp_ssrc_prefix_len, tvb, offset, 1, FALSE );
+                               offset++;
+
+                               prefix_string = g_malloc( prefix_len + 1 );
+                               for ( counter = 0; counter < prefix_len; counter++ )
+                                       prefix_string[ counter ] =
+                                           tvb_get_guint8( tvb, offset + counter );
+                               /* strncpy( prefix_string, pd + offset, prefix_len ); */
+                               prefix_string[ prefix_len ] = '\0';
+                               proto_tree_add_string( sdes_item_tree, hf_rtcp_ssrc_prefix_string, tvb, offset, prefix_len, prefix_string );
+                               g_free( prefix_string );
+                               offset += prefix_len;
+                       }
+                       prefix_string = g_malloc( item_len + 1 );
+                       for ( counter = 0; counter < item_len; counter++ )
+                           prefix_string[ counter ] =
+                               tvb_get_guint8( tvb, offset + counter );
+                       /* strncpy( prefix_string, pd + offset, item_len ); */
+                       prefix_string[ item_len] = 0;
+                       proto_tree_add_string( sdes_item_tree, hf_rtcp_ssrc_text, tvb, offset, item_len, prefix_string );
+                       g_free( prefix_string );
+                       offset += item_len;
+               }
 
-               if ((offset + 1) > end_packet)
-                       return -1;
+               /* Set the length of the items subtree. */
+               proto_item_set_len(ti, offset - items_start_offset);
 
-               len = pd[offset];
-               proto_tree_add_text(rtcp_tree, offset, 1, "Chunk length: %u",
-                       (unsigned) len);
-               offset++;
+               /* 32 bits = 4 bytes, so.....
+                * If offset % 4 != 0, we divide offset by 4, add one and then
+                * multiply by 4 again to reach the boundary
+                */
+               if ( offset % 4 != 0 )
+                       offset = ((offset / 4) + 1 ) * 4;
 
-               if ((offset + len) > end_packet)
-                       return -1;
+               /* Set the length of this chunk. */
+               proto_item_set_len(sdes_item, offset - start_offset);
 
-               proto_tree_add_text(rtcp_tree, offset, len, "Chunk string: %s",
-                       format_text(&pd[offset], len));
-               offset += len;
+               chunk++;
        }
-       return offset;
 }
 
 static int
-dissect_rtcp_sdes(rtcp_hdr_t *hdr, const u_char *pd, int offset,
-       int start_packet, int end_packet, proto_tree *rtcp_tree)
+dissect_rtcp_rr( tvbuff_t *tvb, int offset, proto_tree *tree,
+    unsigned int count )
 {
-       int             cn;
+       unsigned int counter = 1;
+       proto_tree *ssrc_tree = (proto_tree*) NULL;
+       proto_tree *ssrc_sub_tree = (proto_tree*) NULL;
+       proto_tree *high_sec_tree = (proto_tree*) NULL;
+       proto_item *ti = (proto_item*) NULL;
+       guint8 rr_flt;
+       unsigned int cum_nr = 0;
+
+       while ( counter <= count ) {
+               /* Create a new subtree for a length of 24 bytes */
+               ti = proto_tree_add_text(tree, tvb, offset, 24,
+                   "Source %u", counter );
+               ssrc_tree = proto_item_add_subtree( ti, ett_ssrc );
+
+               /* SSRC_n source identifier, 32 bits */
+               proto_tree_add_uint( ssrc_tree, hf_rtcp_ssrc_source, tvb, offset, 4, tvb_get_ntohl( tvb, offset ) );
+               offset += 4;
+
+               ti = proto_tree_add_text(ssrc_tree, tvb, offset, 20, "SSRC contents" );
+               ssrc_sub_tree = proto_item_add_subtree( ti, ett_ssrc_item );
+
+               /* Fraction lost, 8bits */
+               rr_flt = tvb_get_guint8( tvb, offset );
+               proto_tree_add_uint_format( ssrc_sub_tree, hf_rtcp_ssrc_fraction, tvb,
+                   offset, 1, rr_flt, "Fraction lost: %u / 256", rr_flt );
+               offset++;
 
-       for (cn = 0; cn < RTCP_COUNT(hdr); cn++) {
-               offset = dissect_rtcp_sdes_chunk(hdr, cn, pd, offset,
-                       start_packet, end_packet, rtcp_tree);
+               /* Cumulative number of packets lost, 24 bits */
+               cum_nr = tvb_get_ntohl( tvb, offset ) >> 8;
+               proto_tree_add_uint( ssrc_sub_tree, hf_rtcp_ssrc_cum_nr, tvb,
+                   offset, 3, cum_nr );
+               offset += 3;
+
+               /* Extended highest sequence nr received, 32 bits
+                * Just for the sake of it, let's add another subtree
+                * because this might be a little clearer
+                */
+               ti = proto_tree_add_uint( ssrc_tree, hf_rtcp_ssrc_ext_high_seq,
+                   tvb, offset, 4, tvb_get_ntohl( tvb, offset ) );
+               high_sec_tree = proto_item_add_subtree( ti, ett_ssrc_ext_high );
+               /* Sequence number cycles */
+               proto_tree_add_uint( high_sec_tree, hf_rtcp_ssrc_high_cycles,
+                   tvb, offset, 2, tvb_get_ntohs( tvb, offset ) );
+               offset += 2;
+               /* highest sequence number received */
+               proto_tree_add_uint( high_sec_tree, hf_rtcp_ssrc_high_seq,
+                   tvb, offset, 2, tvb_get_ntohs( tvb, offset ) );
+               offset += 2;
+
+               /* Interarrival jitter */
+               proto_tree_add_uint( ssrc_tree, hf_rtcp_ssrc_jitter, tvb,
+                   offset, 4, tvb_get_ntohl( tvb, offset ) );
+               offset += 4;
+
+               /* Last SR timestamp */
+               proto_tree_add_uint( ssrc_tree, hf_rtcp_ssrc_lsr, tvb,
+                   offset, 4, tvb_get_ntohl( tvb, offset ) );
+               offset += 4;
+
+               /* Delay since last SR timestamp */
+               proto_tree_add_uint( ssrc_tree, hf_rtcp_ssrc_dlsr, tvb,
+                   offset, 4, tvb_get_ntohl( tvb, offset ) );
+               offset += 4;
+               counter++;
        }
+
        return offset;
 }
 
 static int
-dissect_one_rtcp(const u_char *pd, int offset, frame_data *fd,
-       proto_tree *tree)
+dissect_rtcp_sr( tvbuff_t *tvb, int offset, proto_tree *tree,
+    unsigned int count )
 {
-       proto_tree      *rtcp_tree;
-       proto_item      *ti;
-       const u_char    *data, *dataend;
-       int             end_offset;
-       int             start_packet;
-       int             end_packet;
-       rtcp_hdr_t      hdr;
-       const char      *ptype;
-
-       data = &pd[offset];
-       dataend = data + END_OF_FRAME;
-       start_packet = offset;
-       end_offset = offset + END_OF_FRAME;
-
-       ti = proto_tree_add_item(tree, proto_rtcp, offset, END_OF_FRAME, NULL);
-       rtcp_tree = proto_item_add_subtree(ti, ett_rtcp);
-
-       memcpy(&hdr, data, END_OF_FRAME < sizeof(rtcp_hdr_t) ?
-               END_OF_FRAME : sizeof(rtcp_hdr_t));
-       hdr.rtcp_length = ntohs(hdr.rtcp_length);
-
-       if (offset >= end_offset)
-               return -1;
-       proto_tree_add_text(rtcp_tree, offset, 1, "Version: %u (%s)",
-               RTCP_VERSION(&hdr),
-               RTCP_VERSION(&hdr) == 3 ? "New Unknown Version" :
-               RTCP_VERSION(&hdr) == 2 ? "RFC 1889 Version" :
-               RTCP_VERSION(&hdr) == 1 ? "First Draft Version" :
-               "Old Vat Version");
-       proto_tree_add_text(rtcp_tree, offset, 1, "Padding: %u",
-               RTCP_PADDING(&hdr));
-       proto_tree_add_text(rtcp_tree, offset, 1, "Count: %u",
-               RTCP_COUNT(&hdr));
-       offset++;
-
-       if (offset >= end_offset)
-               return -1;
-       switch (hdr.rtcp_type) {
-       case RTCP_TYPE_SR:      ptype = "SR: Sender Report"; break;
-       case RTCP_TYPE_RR:      ptype = "RR: Receiver Report"; break;
-       case RTCP_TYPE_SDES:    ptype = "SDES: Source Description"; break;
-       case RTCP_TYPE_BYE:     ptype = "BYE: Goodbye"; break;
-       case RTCP_TYPE_APP:     ptype = "APP: Application-defined"; break;
-       default:                ptype = "Unknown"; break;
-       }
-       proto_tree_add_text(rtcp_tree, offset, 1, "Type: %u (%s)",
-               (u_int) hdr.rtcp_type, ptype);
-       offset++;
-
-       if (offset >= end_offset)
-               return -1;
-       proto_tree_add_text(rtcp_tree, offset, 2, "Length / 4 - 1: %u",
-               (unsigned) hdr.rtcp_length);
-       offset += 2;
-
+#if 0
+       gchar buff[ NTP_TS_SIZE ];
+       char* ptime = tvb_get_ptr( tvb, offset, 8 );
+
+       /* Retreive the NTP timestamp. Using the NTP dissector for this */
+       ntp_fmt_ts( ptime, buff );
+       proto_tree_add_string_format( tree, hf_rtcp_ntp, tvb, offset, 8, ( const char* ) &buff, "NTP timestamp: %s", &buff );
+       free( ptime ); ??????????????????????????????????????????????????????????????????
+       offset += 8;
+#else
        /*
-        * Don't add 1 to length, since it's accounted for above.
+        * XXX - RFC 1889 says this is an NTP timestamp, but that appears
+        * not to be the case.
         */
-       end_packet = offset + hdr.rtcp_length * 4;
-
-       switch (hdr.rtcp_type) {
-       case RTCP_TYPE_RR:
-               offset = dissect_rtcp_rr(&hdr, pd, offset, start_packet,
-                       end_packet, rtcp_tree);
-               break;
-       case RTCP_TYPE_SR:
-               offset = dissect_rtcp_sr(&hdr, pd, offset, start_packet,
-                       end_packet, rtcp_tree);
-               break;
-       case RTCP_TYPE_SDES:
-               offset = dissect_rtcp_sdes(&hdr, pd, offset, start_packet,
-                       end_packet, rtcp_tree);
-               break;
-       default:
-               proto_tree_add_text(rtcp_tree, offset, END_OF_FRAME,
-                       "TYPE NOT HANDLED YET");
-               offset = end_packet;
-               break;
-       }
+       proto_tree_add_text(tree, tvb, offset, 4, "Timestamp, MSW: %u",
+               tvb_get_ntohl(tvb, offset));
+       offset += 4;
+       proto_tree_add_text(tree, tvb, offset, 4, "Timestamp, LSW: %u",
+               tvb_get_ntohl(tvb, offset));
+       offset += 4;
+#endif
+       /* RTP timestamp, 32 bits */
+       proto_tree_add_uint( tree, hf_rtcp_rtp_timestamp, tvb, offset, 4, tvb_get_ntohl( tvb, offset ) );
+       offset += 4;
+       /* Sender's packet count, 32 bits */
+       proto_tree_add_uint( tree, hf_rtcp_sender_pkt_cnt, tvb, offset, 4, tvb_get_ntohl( tvb, offset ) );
+       offset += 4;
+       /* Sender's octet count, 32 bits */
+       proto_tree_add_uint( tree, hf_rtcp_sender_oct_cnt, tvb, offset, 4, tvb_get_ntohl( tvb, offset ) );
+       offset += 4;
 
-       if (offset > 0 && offset < end_packet) {
-               proto_tree_add_text(rtcp_tree, offset, end_packet - offset,
-                       "Extra data (%d bytes)", end_packet - offset);
-       }
-       if (offset < 0)
-               return offset;
-       return end_packet;
+       /* The rest of the packet is equal to the RR packet */
+       if ( count != 0 )
+               offset = dissect_rtcp_rr( tvb, offset, tree, count );
+
+       return offset;
 }
 
-void
-dissect_rtcp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
+static void
+dissect_rtcp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
 {
-       int             end_offset;
-
-       if (check_col(fd, COL_PROTOCOL))
-               col_add_str(fd, COL_PROTOCOL, "RTCP");
-
-       if (!tree)
-               return;
+       proto_item *ti           = NULL;
+       proto_tree *rtcp_tree    = NULL;
+       unsigned int temp_byte   = 0;
+       unsigned int padding_set = 0;
+       unsigned int elem_count  = 0;
+       unsigned int packet_type = 0;
+       unsigned int offset      = 0;
+       guint16 packet_length    = 0;
+
+       if ( check_col( pinfo->cinfo, COL_PROTOCOL ) )   {
+               col_set_str( pinfo->cinfo, COL_PROTOCOL, "RTCP" );
+       }
 
-       end_offset = offset + END_OF_FRAME;
-       while (offset > 0 && offset < end_offset) {
-               offset = dissect_one_rtcp(pd, offset, fd, tree);
+       if ( check_col( pinfo->cinfo, COL_INFO) ) {
+               /* The second octet contains the packet type */
+               /* switch ( pd[ offset + 1 ] ) { */
+               switch ( tvb_get_guint8( tvb, 1 ) ) {
+                       case RTCP_SR:
+                               col_set_str( pinfo->cinfo, COL_INFO, "Sender Report");
+                               break;
+                       case RTCP_RR:
+                               col_set_str( pinfo->cinfo, COL_INFO, "Receiver Report");
+                               break;
+                       case RTCP_SDES:
+                               col_set_str( pinfo->cinfo, COL_INFO, "Source Description");
+                               break;
+                       case RTCP_BYE:
+                               col_set_str( pinfo->cinfo, COL_INFO, "Goodbye");
+                               break;
+                       case RTCP_APP:
+                               col_set_str( pinfo->cinfo, COL_INFO, "Application defined");
+                               break;
+                       case RTCP_FIR:
+                               col_set_str( pinfo->cinfo, COL_INFO, "Full Intra-frame Request (H.261)");
+                               break;
+                       case RTCP_NACK:
+                               col_set_str( pinfo->cinfo, COL_INFO, "Negative Acknowledgement (H.261)");
+                               break;
+                       default:
+                               col_set_str( pinfo->cinfo, COL_INFO, "Unknown packet type");
+                               break;
+               }
        }
-       if (offset < 0) {
-               proto_tree_add_text(tree, end_offset, 0,
-                       "Unexpected end of packet");
+
+       if ( tree ) {
+
+               /*
+                * Check if there are at least 4 bytes left in the frame,
+                * the last 16 bits of those is the length of the current
+                * RTCP message. The last compound message contains padding,
+                * that enables us to break from the while loop.
+                */
+               while ( tvb_bytes_exist( tvb, offset, 4) ) {
+                       /*
+                        * First retreive the packet_type
+                        */
+                       packet_type = tvb_get_guint8( tvb, offset + 1 );
+
+                       /*
+                        * Check if it's a valid type
+                        */
+                       if ( ( packet_type < 192 ) || ( packet_type >  204 ) )
+                               break;
+
+                       /*
+                        * get the packet-length for the complete RTCP packet
+                        */
+                       packet_length = ( tvb_get_ntohs( tvb, offset + 2 ) + 1 ) * 4;
+
+                       ti = proto_tree_add_item(tree, proto_rtcp, tvb, offset, packet_length, FALSE );
+                       rtcp_tree = proto_item_add_subtree( ti, ett_rtcp );
+
+                       temp_byte = tvb_get_guint8( tvb, offset );
+
+                       proto_tree_add_uint( rtcp_tree, hf_rtcp_version, tvb,
+                           offset, 1, RTCP_VERSION( temp_byte ) );
+                       padding_set = RTCP_PADDING( temp_byte );
+                       proto_tree_add_boolean( rtcp_tree, hf_rtcp_padding, tvb,
+                           offset, 1, padding_set );
+                       elem_count = RTCP_COUNT( temp_byte );
+
+                       switch ( packet_type ) {
+                               case RTCP_SR:
+                               case RTCP_RR:
+                                       /* Receiver report count, 5 bits */
+                                       proto_tree_add_uint( rtcp_tree, hf_rtcp_rc, tvb, offset, 1, elem_count );
+                                       offset++;
+                                       /* Packet type, 8 bits */
+                                       proto_tree_add_item( rtcp_tree, hf_rtcp_pt, tvb, offset, 1, FALSE );
+                                       offset++;
+                                       /* Packet length in 32 bit words MINUS one, 16 bits */
+                                       proto_tree_add_uint( rtcp_tree, hf_rtcp_length, tvb, offset, 2, tvb_get_ntohs( tvb, offset ) );
+                                       offset += 2;
+                                       /* Sender Synchronization source, 32 bits */
+                                       proto_tree_add_uint( rtcp_tree, hf_rtcp_ssrc_sender, tvb, offset, 4, tvb_get_ntohl( tvb, offset ) );
+                                       offset += 4;
+
+                                       if ( packet_type == RTCP_SR ) offset = dissect_rtcp_sr( tvb, offset, rtcp_tree, elem_count );
+                                       else offset = dissect_rtcp_rr( tvb, offset, rtcp_tree, elem_count );
+                                       break;
+                               case RTCP_SDES:
+                                       /* Source count, 5 bits */
+                                       proto_tree_add_uint( rtcp_tree, hf_rtcp_sc, tvb, offset, 1, elem_count );
+                                       offset++;
+                                       /* Packet type, 8 bits */
+                                       proto_tree_add_item( rtcp_tree, hf_rtcp_pt, tvb, offset, 1, FALSE );
+                                       offset++;
+                                       /* Packet length in 32 bit words MINUS one, 16 bits */
+                                       proto_tree_add_uint( rtcp_tree, hf_rtcp_length, tvb, offset, 2, tvb_get_ntohs( tvb, offset ) );
+                                       offset += 2;
+                                       dissect_rtcp_sdes( tvb, offset, rtcp_tree, elem_count );
+                                       offset += packet_length - 4;
+                                       break;
+                               case RTCP_BYE:
+                                       /* Source count, 5 bits */
+                                       proto_tree_add_uint( rtcp_tree, hf_rtcp_sc, tvb, offset, 1, elem_count );
+                                       offset++;
+                                       /* Packet type, 8 bits */
+                                       proto_tree_add_item( rtcp_tree, hf_rtcp_pt, tvb, offset, 1, FALSE );
+                                       offset++;
+                                       /* Packet length in 32 bit words MINUS one, 16 bits */
+                                       proto_tree_add_uint( rtcp_tree, hf_rtcp_length, tvb, offset, 2, tvb_get_ntohs( tvb, offset ) );
+                                       offset += 2;
+                                       offset = dissect_rtcp_bye( tvb, offset, rtcp_tree, elem_count );
+                                       break;
+                               case RTCP_APP:
+                                       /* Subtype, 5 bits */
+                                       proto_tree_add_uint( rtcp_tree, hf_rtcp_subtype, tvb, offset, 1, elem_count );
+                                       offset++;
+                                       /* Packet type, 8 bits */
+                                       proto_tree_add_item( rtcp_tree, hf_rtcp_pt, tvb, offset, 1, FALSE );
+                                       offset++;
+                                       /* Packet length in 32 bit words MINUS one, 16 bits */
+                                       proto_tree_add_uint( rtcp_tree, hf_rtcp_length, tvb, offset, 2, tvb_get_ntohs( tvb, offset ) );
+                                       offset += 2;
+                                       offset = dissect_rtcp_app( tvb, offset,
+                                           rtcp_tree, padding_set,
+                                           packet_length - 4 );
+                                       break;
+                               case RTCP_FIR:
+                                       offset = dissect_rtcp_fir( tvb, offset, rtcp_tree );
+                                       break;
+                               case RTCP_NACK:
+                                       offset = dissect_rtcp_nack( tvb, offset, rtcp_tree );
+                                       break;
+                               default:
+                                       /*
+                                        * To prevent endless loops in case of an unknown message type
+                                        * increase offset. Some time the while will end :-)
+                                        */
+                                       offset++;
+                                       break;
+                       }
+               }
+               /* If the padding bit is set, the last octet of the
+                * packet contains the length of the padding
+                * We only have to check for this at the end of the LAST RTCP message
+                */
+               if ( padding_set ) {
+                       /* If everything went according to plan offset should now point to the
+                        * first octet of the padding
+                        */
+                       proto_tree_add_item( rtcp_tree, hf_rtcp_padding_data, tvb, offset, tvb_length_remaining( tvb, offset) - 1, FALSE );
+                       offset += tvb_length_remaining( tvb, offset) - 1;
+                       proto_tree_add_item( rtcp_tree, hf_rtcp_padding_count, tvb, offset, 1, FALSE );
+               }
        }
 }
 
 void
 proto_register_rtcp(void)
 {
-/*        static hf_register_info hf[] = {
-                { &variable,
-                { "Name",           "rtcp.abbreviation", TYPE, VALS_POINTER }},
-        };*/
-       static gint *ett[] = {
+       static hf_register_info hf[] =
+       {
+               {
+                       &hf_rtcp_version,
+                       {
+                               "Version",
+                               "rtcp.version",
+                               FT_UINT8,
+                               BASE_DEC,
+                               VALS(rtcp_version_vals),
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_padding,
+                       {
+                               "Padding",
+                               "rtcp.padding",
+                               FT_BOOLEAN,
+                               BASE_NONE,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_rc,
+                       {
+                               "Reception report count",
+                               "rtcp.rc",
+                               FT_UINT8,
+                               BASE_DEC,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_sc,
+                       {
+                               "Source count",
+                               "rtcp.sc",
+                               FT_UINT8,
+                               BASE_DEC,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_pt,
+                       {
+                               "Packet type",
+                               "rtcp.pt",
+                               FT_UINT8,
+                               BASE_DEC,
+                               VALS( rtcp_packet_type_vals ),
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_length,
+                       {
+                               "Length",
+                               "rtcp.length",
+                               FT_UINT16,
+                               BASE_DEC,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_ssrc_sender,
+                       {
+                               "Sender SSRC",
+                               "rtcp.senderssrc",
+                               FT_UINT32,
+                               BASE_DEC,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_ntp,
+                       {
+                               "NTP timestamp",
+                               "rtcp.timestamp.ntp",
+                               FT_STRING,
+                               BASE_NONE,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_rtp_timestamp,
+                       {
+                               "RTP timestamp",
+                               "rtcp.timestamp.rtp",
+                               FT_UINT32,
+                               BASE_DEC,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_sender_pkt_cnt,
+                       {
+                               "Sender's packet count",
+                               "rtcp.sender.packetcount",
+                               FT_UINT32,
+                               BASE_DEC,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_sender_oct_cnt,
+                       {
+                               "Sender's octet count",
+                               "rtcp.sender.octetcount",
+                               FT_UINT32,
+                               BASE_DEC,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_ssrc_source,
+                       {
+                               "Identifier",
+                               "rtcp.ssrc.identifier",
+                               FT_UINT32,
+                               BASE_DEC,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_ssrc_fraction,
+                       {
+                               "Fraction lost",
+                               "rtcp.ssrc.fraction",
+                               FT_UINT8,
+                               BASE_DEC,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_ssrc_cum_nr,
+                       {
+                               "Cumulative number of packets lost",
+                               "rtcp.ssrc.cum_nr",
+                               FT_UINT32,
+                               BASE_DEC,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_ssrc_ext_high_seq,
+                       {
+                               "Extended highest sequence number received",
+                               "rtcp.ssrc.ext_high",
+                               FT_UINT32,
+                               BASE_DEC,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_ssrc_high_seq,
+                       {
+                               "Highest sequence number received",
+                               "rtcp.ssrc.high_seq",
+                               FT_UINT16,
+                               BASE_DEC,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_ssrc_high_cycles,
+                       {
+                               "Sequence number cycles count",
+                               "rtcp.ssrc.high_cycles",
+                               FT_UINT16,
+                               BASE_DEC,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_ssrc_jitter,
+                       {
+                               "Interarrival jitter",
+                               "rtcp.ssrc.jitter",
+                               FT_UINT32,
+                               BASE_DEC,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_ssrc_lsr,
+                       {
+                               "Last SR timestamp",
+                               "rtcp.ssrc.lsr",
+                               FT_UINT32,
+                               BASE_DEC,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_ssrc_dlsr,
+                       {
+                               "Delay since last SR timestamp",
+                               "rtcp.ssrc.dlsr",
+                               FT_UINT32,
+                               BASE_DEC,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_ssrc_csrc,
+                       {
+                               "SSRC / CSRC identifier",
+                               "rtcp.sdes.ssrc_csrc",
+                               FT_UINT32,
+                               BASE_DEC,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_ssrc_type,
+                       {
+                               "Type",
+                               "rtcp.sdes.type",
+                               FT_UINT8,
+                               BASE_DEC,
+                               VALS( rtcp_sdes_type_vals ),
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_ssrc_length,
+                       {
+                               "Length",
+                               "rtcp.sdes.length",
+                               FT_UINT32,
+                               BASE_DEC,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_ssrc_text,
+                       {
+                               "Text",
+                               "rtcp.sdes.text",
+                               FT_STRING,
+                               BASE_NONE,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_ssrc_prefix_len,
+                       {
+                               "Prefix length",
+                               "rtcp.sdes.prefix.length",
+                               FT_UINT8,
+                               BASE_DEC,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_ssrc_prefix_string,
+                       {
+                               "Prefix string",
+                               "rtcp.sdes.prefix.string",
+                               FT_STRING,
+                               BASE_NONE,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_subtype,
+                       {
+                               "Subtype",
+                               "rtcp.app.subtype",
+                               FT_UINT8,
+                               BASE_DEC,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_name_ascii,
+                       {
+                               "Name (ASCII)",
+                               "rtcp.app.name",
+                               FT_STRING,
+                               BASE_NONE,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_app_data,
+                       {
+                               "Application specific data",
+                               "rtcp.app.data",
+                               FT_BYTES,
+                               BASE_NONE,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_fsn,
+                       {
+                               "First sequence number",
+                               "rtcp.nack.fsn",
+                               FT_UINT16,
+                               BASE_DEC,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_blp,
+                       {
+                               "Bitmask of following lost packets",
+                               "rtcp.nack.blp",
+                               FT_UINT16,
+                               BASE_DEC,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_padding_count,
+                       {
+                               "Padding count",
+                               "rtcp.padding.count",
+                               FT_UINT8,
+                               BASE_DEC,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+               {
+                       &hf_rtcp_padding_data,
+                       {
+                               "Padding data",
+                               "rtcp.padding.data",
+                               FT_BYTES,
+                               BASE_NONE,
+                               NULL,
+                               0x0,
+                               "", HFILL
+                       }
+               },
+};
+
+       static gint *ett[] =
+       {
                &ett_rtcp,
+               &ett_ssrc,
+               &ett_ssrc_item,
+               &ett_ssrc_ext_high,
+               &ett_sdes,
+               &ett_sdes_item,
        };
 
-       proto_rtcp = proto_register_protocol("RTP Control Protocol", "rtcp");
- /*       proto_register_field_array(proto_rtcp, hf, array_length(hf));*/
+
+       proto_rtcp = proto_register_protocol("Real-time Transport Control Protocol",
+           "RTCP", "rtcp");
+       proto_register_field_array(proto_rtcp, hf, array_length(hf));
        proto_register_subtree_array(ett, array_length(ett));
+
+       register_dissector("rtcp", dissect_rtcp, proto_rtcp);
+
+#if 0
+       register_init_routine( &rtcp_init );
+#endif
+}
+
+void
+proto_reg_handoff_rtcp(void)
+{
+       dissector_handle_t rtcp_handle;
+
+       /*
+        * Register this dissector as one that can be selected by a
+        * UDP port number.
+        */
+       rtcp_handle = find_dissector("rtcp");
+       dissector_add_handle("udp.port", rtcp_handle);
 }