2 * Routines for RTCP packet disassembly
4 * Jason Lango <jal@netapp.com>
6 * $Id: packet-rtcp.c,v 1.5 2000/09/11 16:16:02 gram Exp $
8 * Ethereal - Network traffic analyzer
9 * By Gerald Combs <gerald@zing.org>
10 * Copyright 1998 Gerald Combs
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #ifdef HAVE_SYS_TYPES_H
33 #include <sys/types.h>
36 #ifdef HAVE_NETINET_IN_H
37 #include <netinet/in.h>
45 #include "packet-rtcp.h"
48 static int proto_rtcp = -1;
50 static gint ett_rtcp = -1;
52 #define _RTCP_FLAG_BITS(hdr, s, n) \
53 ((u_int)(((hdr)->rtcp_flag_bits >> (8 - (s) - (n))) & ((1 << (n)) - 1)))
54 #define RTCP_VERSION(hdr) _RTCP_FLAG_BITS(hdr, 0, 2)
55 #define RTCP_PADDING(hdr) _RTCP_FLAG_BITS(hdr, 2, 1)
56 #define RTCP_COUNT(hdr) _RTCP_FLAG_BITS(hdr, 3, 5)
58 #define RTCP_TYPE_SR 200 /* Sender Report */
59 #define RTCP_TYPE_RR 201 /* Receiver Report */
60 #define RTCP_TYPE_SDES 202 /* Source Description */
61 #define RTCP_TYPE_BYE 203 /* Goodbye */
62 #define RTCP_TYPE_APP 204 /* Application-defined */
64 typedef struct rtcp_hdr {
65 guint8 rtcp_flag_bits;
66 guint8 rtcp_type; /* packet type */
67 guint16 rtcp_length; /* length in 32 bit words minus 1 */
70 typedef struct rtcp_report {
71 guint32 rtcp_rr_ssrc; /* SSRC of source */
72 guint8 rtcp_rr_flt; /* fraction lost */
73 guint8 rtcp_rr_cplthi; /* hi-byte of cplt */
74 guint16 rtcp_rr_cplt; /* cumulative packets lost */
75 guint32 rtcp_rr_xhiseq; /* extended highest seq num rcvd */
76 guint32 rtcp_rr_jitter; /* interarrival jitter */
77 guint32 rtcp_rr_lsr; /* middle bits of last SR timestamp */
78 guint32 rtcp_rr_dlsr; /* delay since last SR */
82 dissect_rtcp_report(rtcp_hdr_t *hdr, int sn, const u_char *pd, int offset,
83 int start_packet, int end_packet, proto_tree *rtcp_tree)
85 int end_offset = offset + END_OF_FRAME;
88 if (offset >= end_offset)
91 memcpy(&rep, &pd[offset], sizeof(rtcp_report_t) <= END_OF_FRAME ?
92 sizeof(rtcp_report_t) : END_OF_FRAME);
94 rep.rtcp_rr_ssrc = ntohl(rep.rtcp_rr_ssrc);
95 rep.rtcp_rr_cplt = ntohs(rep.rtcp_rr_cplt);
96 rep.rtcp_rr_xhiseq = ntohl(rep.rtcp_rr_xhiseq);
97 rep.rtcp_rr_jitter = ntohl(rep.rtcp_rr_jitter);
98 rep.rtcp_rr_lsr = ntohl(rep.rtcp_rr_lsr);
99 rep.rtcp_rr_dlsr = ntohl(rep.rtcp_rr_dlsr);
101 if ((offset + sizeof(rtcp_report_t)) > end_offset) {
102 proto_tree_add_text(rtcp_tree, NullTVB, offset, 0,
103 "Warning: Bad packet length -- "
104 "data might be incorrect");
107 proto_tree_add_text(rtcp_tree, NullTVB, offset, 4,
108 "Source %d SSRC: %u", sn + 1, rep.rtcp_rr_ssrc);
111 proto_tree_add_text(rtcp_tree, NullTVB, offset, 1,
112 "Fraction lost: %u / 256", (unsigned) rep.rtcp_rr_flt);
115 proto_tree_add_text(rtcp_tree, NullTVB, offset, 3,
116 "Cumulative Packets Lost: %lu",
117 (((unsigned long) rep.rtcp_rr_cplthi) << 16) +
118 (unsigned long) rep.rtcp_rr_cplt);
121 proto_tree_add_text(rtcp_tree, NullTVB, offset, 4,
122 "Extended Highest Seq #: %lu",
123 (unsigned long) rep.rtcp_rr_xhiseq);
126 proto_tree_add_text(rtcp_tree, NullTVB, offset, 4,
127 "Jitter: %lu", (unsigned long) rep.rtcp_rr_jitter);
130 proto_tree_add_text(rtcp_tree, NullTVB, offset, 4,
131 "Last SR timestamp (middle): %lu",
132 (unsigned long) rep.rtcp_rr_lsr);
135 proto_tree_add_text(rtcp_tree, NullTVB, offset, 4,
136 "Delay Since Last SR: %lu",
137 (unsigned long) rep.rtcp_rr_dlsr);
143 typedef struct rtcp_rr {
144 guint32 rtcp_rr_ssrc;
148 dissect_rtcp_rr(rtcp_hdr_t *hdr, const u_char *pd, int offset,
149 int start_packet, int end_packet, proto_tree *rtcp_tree)
151 int end_offset = offset + END_OF_FRAME;
155 memcpy(&rr, &pd[offset], sizeof(rtcp_rr_t) < END_OF_FRAME ?
156 sizeof(rtcp_rr_t) : END_OF_FRAME);
157 rr.rtcp_rr_ssrc = ntohl(rr.rtcp_rr_ssrc);
159 if ((offset + sizeof(rtcp_rr_t)) >= end_offset)
161 proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, "Sender SSRC: %u",
165 for (sn = 0; sn < RTCP_COUNT(hdr); sn++) {
166 offset = dissect_rtcp_report(hdr, sn, pd, offset, start_packet,
167 end_packet, rtcp_tree);
173 typedef struct rtcp_sr {
174 guint32 rtcp_sr_ssrc;
175 guint32 rtcp_sr_ntp_hi; /* MSW of NTP timestamp */
176 guint32 rtcp_sr_ntp_lo; /* LSW of NTP timestamp */
177 guint32 rtcp_sr_rtp_time; /* RTP timestamp */
178 guint32 rtcp_sr_npackets; /* sender's packet count */
179 guint32 rtcp_sr_nbytes; /* sender's octet count */
183 dissect_rtcp_sr(rtcp_hdr_t *hdr, const u_char *pd, int offset,
184 int start_packet, int end_packet, proto_tree *rtcp_tree)
186 int end_offset = offset + END_OF_FRAME;
190 memcpy(&sr, &pd[offset], sizeof(rtcp_sr_t) < END_OF_FRAME ?
191 sizeof(rtcp_sr_t) : END_OF_FRAME);
192 sr.rtcp_sr_ssrc = ntohl(sr.rtcp_sr_ssrc);
193 sr.rtcp_sr_ntp_hi = ntohl(sr.rtcp_sr_ntp_hi);
194 sr.rtcp_sr_ntp_lo = ntohl(sr.rtcp_sr_ntp_lo);
195 sr.rtcp_sr_rtp_time = ntohl(sr.rtcp_sr_rtp_time);
196 sr.rtcp_sr_npackets = ntohl(sr.rtcp_sr_npackets);
197 sr.rtcp_sr_nbytes = ntohl(sr.rtcp_sr_nbytes);
199 if ((offset + sizeof(rtcp_sr_t)) > end_offset) {
200 proto_tree_add_text(rtcp_tree, NullTVB, offset, 0,
201 "Warning: Bad packet length -- "
202 "data might be incorrect");
205 proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, "Sender's SSRC: %u",
208 proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, "NTP timestamp, MSW: %u",
211 proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, "NTP timestamp, LSW: %u",
214 proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, "RTP timestamp: %u",
215 sr.rtcp_sr_rtp_time);
217 proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, "Sender's packet count: %u",
218 sr.rtcp_sr_npackets);
220 proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, "Sender's octet count: %u",
224 for (sn = 0; sn < RTCP_COUNT(hdr); sn++) {
225 offset = dissect_rtcp_report(hdr, sn, pd, offset, start_packet,
226 end_packet, rtcp_tree);
232 static struct rtcp_chunk_type {
235 } rtcp_chunk_types[] = {
236 { 1, "CNAME (user and domain)" },
237 { 2, "NAME (common name)" },
238 { 3, "EMAIL (e-mail address)" },
239 { 4, "PHONE (phone number)" },
240 { 5, "LOC (geographic location)" },
241 { 6, "TOOL (name/version of source app)" },
242 { 7, "NOTE (note about source)" },
243 { 8, "PRIV (private extensions)" },
247 static struct rtcp_chunk_type *
248 rtcp_find_chunk_type(int type)
250 struct rtcp_chunk_type *tt = rtcp_chunk_types;
251 static struct rtcp_chunk_type unk = { 0, "UNKNOWN" };
252 for (; tt->type; tt++) {
253 if (type == tt->type)
260 dissect_rtcp_sdes_chunk(rtcp_hdr_t *hdr, int cn, const u_char *pd, int offset,
261 int start_packet, int end_packet, proto_tree *rtcp_tree)
265 struct rtcp_chunk_type *ctype;
267 if ((offset + 4) > end_packet)
269 proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, "Chunk %d SSRC: %u",
270 cn + 1, pntohl(&pd[offset]));
274 if ((offset + 1) > end_packet)
279 int pad_start = offset;
281 /* NULL terminator -- align to next 32 bit boundary */
282 if ((offset - start_packet) & 3) {
283 offset += 4 - ((offset - start_packet) & 3);
285 proto_tree_add_text(rtcp_tree, NullTVB, pad_start,
287 "(end of chunk and alignment padding)");
291 ctype = rtcp_find_chunk_type(type);
293 proto_tree_add_text(rtcp_tree, NullTVB, offset, 1, "Chunk type: %s",
297 if ((offset + 1) > end_packet)
301 proto_tree_add_text(rtcp_tree, NullTVB, offset, 1, "Chunk length: %u",
305 if ((offset + len) > end_packet)
308 proto_tree_add_text(rtcp_tree, NullTVB, offset, len, "Chunk string: %s",
309 format_text(&pd[offset], len));
316 dissect_rtcp_sdes(rtcp_hdr_t *hdr, const u_char *pd, int offset,
317 int start_packet, int end_packet, proto_tree *rtcp_tree)
321 for (cn = 0; cn < RTCP_COUNT(hdr); cn++) {
322 offset = dissect_rtcp_sdes_chunk(hdr, cn, pd, offset,
323 start_packet, end_packet, rtcp_tree);
329 dissect_one_rtcp(const u_char *pd, int offset, frame_data *fd,
332 proto_tree *rtcp_tree;
334 const u_char *data, *dataend;
342 dataend = data + END_OF_FRAME;
343 start_packet = offset;
344 end_offset = offset + END_OF_FRAME;
346 ti = proto_tree_add_item(tree, proto_rtcp, NullTVB, offset, END_OF_FRAME, FALSE);
347 rtcp_tree = proto_item_add_subtree(ti, ett_rtcp);
349 memcpy(&hdr, data, END_OF_FRAME < sizeof(rtcp_hdr_t) ?
350 END_OF_FRAME : sizeof(rtcp_hdr_t));
351 hdr.rtcp_length = ntohs(hdr.rtcp_length);
353 if (offset >= end_offset)
355 proto_tree_add_text(rtcp_tree, NullTVB, offset, 1, "Version: %u (%s)",
357 RTCP_VERSION(&hdr) == 3 ? "New Unknown Version" :
358 RTCP_VERSION(&hdr) == 2 ? "RFC 1889 Version" :
359 RTCP_VERSION(&hdr) == 1 ? "First Draft Version" :
361 proto_tree_add_text(rtcp_tree, NullTVB, offset, 1, "Padding: %u",
363 proto_tree_add_text(rtcp_tree, NullTVB, offset, 1, "Count: %u",
367 if (offset >= end_offset)
369 switch (hdr.rtcp_type) {
370 case RTCP_TYPE_SR: ptype = "SR: Sender Report"; break;
371 case RTCP_TYPE_RR: ptype = "RR: Receiver Report"; break;
372 case RTCP_TYPE_SDES: ptype = "SDES: Source Description"; break;
373 case RTCP_TYPE_BYE: ptype = "BYE: Goodbye"; break;
374 case RTCP_TYPE_APP: ptype = "APP: Application-defined"; break;
375 default: ptype = "Unknown"; break;
377 proto_tree_add_text(rtcp_tree, NullTVB, offset, 1, "Type: %u (%s)",
378 (u_int) hdr.rtcp_type, ptype);
381 if (offset >= end_offset)
383 proto_tree_add_text(rtcp_tree, NullTVB, offset, 2, "Length / 4 - 1: %u",
384 (unsigned) hdr.rtcp_length);
388 * Don't add 1 to length, since it's accounted for above.
390 end_packet = offset + hdr.rtcp_length * 4;
392 switch (hdr.rtcp_type) {
394 offset = dissect_rtcp_rr(&hdr, pd, offset, start_packet,
395 end_packet, rtcp_tree);
398 offset = dissect_rtcp_sr(&hdr, pd, offset, start_packet,
399 end_packet, rtcp_tree);
402 offset = dissect_rtcp_sdes(&hdr, pd, offset, start_packet,
403 end_packet, rtcp_tree);
406 proto_tree_add_text(rtcp_tree, NullTVB, offset, END_OF_FRAME,
407 "TYPE NOT HANDLED YET");
412 if (offset > 0 && offset < end_packet) {
413 proto_tree_add_text(rtcp_tree, NullTVB, offset, end_packet - offset,
414 "Extra data (%d bytes)", end_packet - offset);
422 dissect_rtcp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
426 OLD_CHECK_DISPLAY_AS_DATA(proto_rtcp, pd, offset, fd, tree);
428 if (check_col(fd, COL_PROTOCOL))
429 col_add_str(fd, COL_PROTOCOL, "RTCP");
434 end_offset = offset + END_OF_FRAME;
435 while (offset > 0 && offset < end_offset) {
436 offset = dissect_one_rtcp(pd, offset, fd, tree);
439 proto_tree_add_text(tree, NullTVB, end_offset, 0,
440 "Unexpected end of packet");
445 proto_register_rtcp(void)
447 /* static hf_register_info hf[] = {
449 { "Name", "rtcp.abbreviation", TYPE, VALS_POINTER }},
451 static gint *ett[] = {
455 proto_rtcp = proto_register_protocol("RTP Control Protocol", "rtcp");
456 /* proto_register_field_array(proto_rtcp, hf, array_length(hf));*/
457 proto_register_subtree_array(ett, array_length(ett));