Make the "Preferences" dialog box use the new utilities to make the Esc
[obnox/wireshark/wip.git] / packet-rtcp.c
1 /* packet-rtcp.c
2  * Routines for RTCP packet disassembly
3  *
4  * Jason Lango <jal@netapp.com>
5  *
6  * $Id: packet-rtcp.c,v 1.1 2000/04/21 01:45:56 guy Exp $
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@zing.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * 
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.
17  * 
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.
22  * 
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.
26  *
27  *
28  */
29
30 #include "config.h"
31
32 #ifdef HAVE_SYS_TYPES_H
33 #include <sys/types.h>
34 #endif
35
36 #ifdef HAVE_NETINET_IN_H
37 #include <netinet/in.h>
38 #endif
39
40 #include <string.h>
41 #include <ctype.h>
42
43 #include <glib.h>
44 #include "packet.h"
45 #include "packet-rtcp.h"
46
47 static int proto_rtcp = -1;
48
49 static gint ett_rtcp = -1;
50
51 #define _RTCP_FLAG_BITS(hdr, s, n) \
52         ((u_int)(((hdr)->rtcp_flag_bits >> (8 - (s) - (n))) & ((1 << (n)) - 1)))
53 #define RTCP_VERSION(hdr)       _RTCP_FLAG_BITS(hdr, 0, 2)
54 #define RTCP_PADDING(hdr)       _RTCP_FLAG_BITS(hdr, 2, 1)
55 #define RTCP_COUNT(hdr)         _RTCP_FLAG_BITS(hdr, 3, 5)
56
57 #define RTCP_TYPE_SR            200     /* Sender Report */
58 #define RTCP_TYPE_RR            201     /* Receiver Report */
59 #define RTCP_TYPE_SDES          202     /* Source Description */
60 #define RTCP_TYPE_BYE           203     /* Goodbye */
61 #define RTCP_TYPE_APP           204     /* Application-defined */
62
63 typedef struct rtcp_hdr {
64         guint8  rtcp_flag_bits;
65         guint8  rtcp_type;              /* packet type */
66         guint16 rtcp_length;            /* length in 32 bit words minus 1 */
67 } rtcp_hdr_t;
68
69 typedef struct rtcp_report {
70         guint32 rtcp_rr_ssrc;           /* SSRC of source */
71         guint8  rtcp_rr_flt;            /* fraction lost */
72         guint8  rtcp_rr_cplthi;         /* hi-byte of cplt */
73         guint16 rtcp_rr_cplt;           /* cumulative packets lost */
74         guint32 rtcp_rr_xhiseq;         /* extended highest seq num rcvd */
75         guint32 rtcp_rr_jitter;         /* interarrival jitter */
76         guint32 rtcp_rr_lsr;            /* middle bits of last SR timestamp */
77         guint32 rtcp_rr_dlsr;           /* delay since last SR */
78 } rtcp_report_t;
79
80 static int
81 dissect_rtcp_report(rtcp_hdr_t *hdr, int sn, const u_char *pd, int offset,
82         int start_packet, int end_packet, proto_tree *rtcp_tree)
83 {
84         int             end_offset = offset + END_OF_FRAME;
85         rtcp_report_t   rep;
86
87         if (offset >= end_offset)
88                 return -1;
89
90         memcpy(&rep, &pd[offset], sizeof(rtcp_report_t) <= END_OF_FRAME ?
91                 sizeof(rtcp_report_t) : END_OF_FRAME);
92
93         rep.rtcp_rr_ssrc = ntohl(rep.rtcp_rr_ssrc);
94         rep.rtcp_rr_cplt = ntohs(rep.rtcp_rr_cplt);
95         rep.rtcp_rr_xhiseq = ntohl(rep.rtcp_rr_xhiseq);
96         rep.rtcp_rr_jitter = ntohl(rep.rtcp_rr_jitter);
97         rep.rtcp_rr_lsr = ntohl(rep.rtcp_rr_lsr);
98         rep.rtcp_rr_dlsr = ntohl(rep.rtcp_rr_dlsr);
99
100         if ((offset + sizeof(rtcp_report_t)) > end_offset) {
101                 proto_tree_add_text(rtcp_tree, offset, 0,
102                         "Warning: Bad packet length -- "
103                         "data might be incorrect");
104         }
105
106         proto_tree_add_text(rtcp_tree, offset, 4,
107                 "Source %d SSRC: %u", sn + 1, rep.rtcp_rr_ssrc);
108         offset += 4;
109
110         proto_tree_add_text(rtcp_tree, offset, 1,
111                 "Fraction lost: %u / 256", (unsigned) rep.rtcp_rr_flt);
112         offset += 1;
113
114         proto_tree_add_text(rtcp_tree, offset, 3,
115                 "Cumulative Packets Lost: %lu",
116                 (((unsigned long) rep.rtcp_rr_cplthi) << 16) +
117                 (unsigned long) rep.rtcp_rr_cplt);
118         offset += 3;
119
120         proto_tree_add_text(rtcp_tree, offset, 4,
121                 "Extended Highest Seq #: %lu",
122                 (unsigned long) rep.rtcp_rr_xhiseq);
123         offset += 4;
124
125         proto_tree_add_text(rtcp_tree, offset, 4,
126                 "Jitter: %lu", (unsigned long) rep.rtcp_rr_jitter);
127         offset += 4;
128
129         proto_tree_add_text(rtcp_tree, offset, 4,
130                 "Last SR timestamp (middle): %lu",
131                 (unsigned long) rep.rtcp_rr_lsr);
132         offset += 4;
133
134         proto_tree_add_text(rtcp_tree, offset, 4,
135                 "Delay Since Last SR: %lu",
136                 (unsigned long) rep.rtcp_rr_dlsr);
137         offset += 4;
138
139         return offset;
140 }
141
142 typedef struct rtcp_rr {
143         guint32 rtcp_rr_ssrc;
144 } rtcp_rr_t;
145
146 static int
147 dissect_rtcp_rr(rtcp_hdr_t *hdr, const u_char *pd, int offset,
148         int start_packet, int end_packet, proto_tree *rtcp_tree)
149 {
150         int             end_offset = offset + END_OF_FRAME; 
151         rtcp_rr_t       rr;
152         int             sn;
153
154         memcpy(&rr, &pd[offset], sizeof(rtcp_rr_t) < END_OF_FRAME ?
155                 sizeof(rtcp_rr_t) : END_OF_FRAME);
156         rr.rtcp_rr_ssrc = ntohl(rr.rtcp_rr_ssrc);
157
158         if ((offset + sizeof(rtcp_rr_t)) >= end_offset)
159                 return -1;
160         proto_tree_add_text(rtcp_tree, offset, 4, "Sender SSRC: %u",
161                 rr.rtcp_rr_ssrc);
162         offset += 4;
163
164         for (sn = 0; sn < RTCP_COUNT(hdr); sn++) {
165                 offset = dissect_rtcp_report(hdr, sn, pd, offset, start_packet,
166                         end_packet, rtcp_tree);
167         }
168
169         return offset;
170 }
171
172 typedef struct rtcp_sr {
173         guint32 rtcp_sr_ssrc;
174         guint32 rtcp_sr_ntp_hi;         /* MSW of NTP timestamp */
175         guint32 rtcp_sr_ntp_lo;         /* LSW of NTP timestamp */
176         guint32 rtcp_sr_rtp_time;       /* RTP timestamp */
177         guint32 rtcp_sr_npackets;       /* sender's packet count */
178         guint32 rtcp_sr_nbytes;         /* sender's octet count */
179 } rtcp_sr_t;
180
181 static int
182 dissect_rtcp_sr(rtcp_hdr_t *hdr, const u_char *pd, int offset,
183         int start_packet, int end_packet, proto_tree *rtcp_tree)
184 {
185         int             end_offset = offset + END_OF_FRAME; 
186         rtcp_sr_t       sr;
187         int             sn;
188
189         memcpy(&sr, &pd[offset], sizeof(rtcp_sr_t) < END_OF_FRAME ?
190                 sizeof(rtcp_sr_t) : END_OF_FRAME);
191         sr.rtcp_sr_ssrc = ntohl(sr.rtcp_sr_ssrc);
192         sr.rtcp_sr_ntp_hi = ntohl(sr.rtcp_sr_ntp_hi);
193         sr.rtcp_sr_ntp_lo = ntohl(sr.rtcp_sr_ntp_lo);
194         sr.rtcp_sr_rtp_time = ntohl(sr.rtcp_sr_rtp_time);
195         sr.rtcp_sr_npackets = ntohl(sr.rtcp_sr_npackets);
196         sr.rtcp_sr_nbytes = ntohl(sr.rtcp_sr_nbytes);
197
198         if ((offset + sizeof(rtcp_sr_t)) > end_offset) {
199                 proto_tree_add_text(rtcp_tree, offset, 0,
200                         "Warning: Bad packet length -- "
201                         "data might be incorrect");
202         }
203
204         proto_tree_add_text(rtcp_tree, offset, 4, "Sender's SSRC: %u",
205                 sr.rtcp_sr_ssrc);
206         offset += 4;
207         proto_tree_add_text(rtcp_tree, offset, 4, "NTP timestamp, MSW: %u",
208                 sr.rtcp_sr_ntp_hi);
209         offset += 4;
210         proto_tree_add_text(rtcp_tree, offset, 4, "NTP timestamp, LSW: %u",
211                 sr.rtcp_sr_ntp_lo);
212         offset += 4;
213         proto_tree_add_text(rtcp_tree, offset, 4, "RTP timestamp: %u",
214                 sr.rtcp_sr_rtp_time);
215         offset += 4;
216         proto_tree_add_text(rtcp_tree, offset, 4, "Sender's packet count: %u",
217                 sr.rtcp_sr_npackets);
218         offset += 4;
219         proto_tree_add_text(rtcp_tree, offset, 4, "Sender's octet count: %u",
220                 sr.rtcp_sr_nbytes);
221         offset += 4;
222
223         for (sn = 0; sn < RTCP_COUNT(hdr); sn++) {
224                 offset = dissect_rtcp_report(hdr, sn, pd, offset, start_packet,
225                         end_packet, rtcp_tree);
226         }
227
228         return offset;
229 }
230
231 static struct rtcp_chunk_type {
232         int             type;
233         const char      *name;
234 } rtcp_chunk_types[] = {
235         { 1, "CNAME (user and domain)" },
236         { 2, "NAME (common name)" },
237         { 3, "EMAIL (e-mail address)" },
238         { 4, "PHONE (phone number)" },
239         { 5, "LOC (geographic location)" },
240         { 6, "TOOL (name/version of source app)" },
241         { 7, "NOTE (note about source)" },
242         { 8, "PRIV (private extensions)" },
243         { 0, 0 }
244 };
245
246 static struct rtcp_chunk_type *
247 rtcp_find_chunk_type(int type)
248 {
249         struct rtcp_chunk_type *tt = rtcp_chunk_types;
250         static struct rtcp_chunk_type unk = { 0, "UNKNOWN" };
251         for (; tt->type; tt++) {
252                 if (type == tt->type)
253                         return tt;
254         }
255         return &unk;
256 }
257
258 static int
259 dissect_rtcp_sdes_chunk(rtcp_hdr_t *hdr, int cn, const u_char *pd, int offset,
260         int start_packet, int end_packet, proto_tree *rtcp_tree)
261 {
262         unsigned        type;
263         unsigned        len;
264         struct rtcp_chunk_type *ctype;
265
266         if ((offset + 4) > end_packet)
267                 return -1;
268         proto_tree_add_text(rtcp_tree, offset, 4, "Chunk %d SSRC: %u",
269                 cn + 1, pntohl(&pd[offset]));
270         offset += 4;
271
272         for (;;) {
273                 if ((offset + 1) > end_packet)
274                         return -1;
275
276                 type = pd[offset];
277                 if (type == 0) {
278                         int pad_start = offset;
279                         offset++;
280                         /* NULL terminator -- align to next 32 bit boundary */
281                         if ((offset - start_packet) & 3) {
282                                 offset += 4 - ((offset - start_packet) & 3);
283                         }
284                         proto_tree_add_text(rtcp_tree, pad_start,
285                                 offset - pad_start,
286                                 "(end of chunk and alignment padding)");
287                         break;
288                 }
289
290                 ctype = rtcp_find_chunk_type(type);
291
292                 proto_tree_add_text(rtcp_tree, offset, 1, "Chunk type: %s",
293                         ctype->name);
294                 offset++;
295
296                 if ((offset + 1) > end_packet)
297                         return -1;
298
299                 len = pd[offset];
300                 proto_tree_add_text(rtcp_tree, offset, 1, "Chunk length: %u",
301                         (unsigned) len);
302                 offset++;
303
304                 if ((offset + len) > end_packet)
305                         return -1;
306
307                 proto_tree_add_text(rtcp_tree, offset, len, "Chunk string: %s",
308                         format_text(&pd[offset], len));
309                 offset += len;
310         }
311         return offset;
312 }
313
314 static int
315 dissect_rtcp_sdes(rtcp_hdr_t *hdr, const u_char *pd, int offset,
316         int start_packet, int end_packet, proto_tree *rtcp_tree)
317 {
318         int             cn;
319
320         for (cn = 0; cn < RTCP_COUNT(hdr); cn++) {
321                 offset = dissect_rtcp_sdes_chunk(hdr, cn, pd, offset,
322                         start_packet, end_packet, rtcp_tree);
323         }
324         return offset;
325 }
326
327 static int
328 dissect_one_rtcp(const u_char *pd, int offset, frame_data *fd,
329         proto_tree *tree)
330 {
331         proto_tree      *rtcp_tree;
332         proto_item      *ti;
333         const u_char    *data, *dataend;
334         int             end_offset;
335         int             start_packet;
336         int             end_packet;
337         rtcp_hdr_t      hdr;
338         const char      *ptype;
339
340         data = &pd[offset];
341         dataend = data + END_OF_FRAME;
342         start_packet = offset;
343         end_offset = offset + END_OF_FRAME;
344
345         ti = proto_tree_add_item(tree, proto_rtcp, offset, END_OF_FRAME, NULL);
346         rtcp_tree = proto_item_add_subtree(ti, ett_rtcp);
347
348         memcpy(&hdr, data, END_OF_FRAME < sizeof(rtcp_hdr_t) ?
349                 END_OF_FRAME : sizeof(rtcp_hdr_t));
350         hdr.rtcp_length = ntohs(hdr.rtcp_length);
351
352         if (offset >= end_offset)
353                 return -1;
354         proto_tree_add_text(rtcp_tree, offset, 1, "Version: %u (%s)",
355                 RTCP_VERSION(&hdr),
356                 RTCP_VERSION(&hdr) == 3 ? "New Unknown Version" :
357                 RTCP_VERSION(&hdr) == 2 ? "RFC 1889 Version" :
358                 RTCP_VERSION(&hdr) == 1 ? "First Draft Version" :
359                 "Old Vat Version");
360         proto_tree_add_text(rtcp_tree, offset, 1, "Padding: %u",
361                 RTCP_PADDING(&hdr));
362         proto_tree_add_text(rtcp_tree, offset, 1, "Count: %u",
363                 RTCP_COUNT(&hdr));
364         offset++;
365
366         if (offset >= end_offset)
367                 return -1;
368         switch (hdr.rtcp_type) {
369         case RTCP_TYPE_SR:      ptype = "SR: Sender Report"; break;
370         case RTCP_TYPE_RR:      ptype = "RR: Receiver Report"; break;
371         case RTCP_TYPE_SDES:    ptype = "SDES: Source Description"; break;
372         case RTCP_TYPE_BYE:     ptype = "BYE: Goodbye"; break;
373         case RTCP_TYPE_APP:     ptype = "APP: Application-defined"; break;
374         default:                ptype = "Unknown"; break;
375         }
376         proto_tree_add_text(rtcp_tree, offset, 1, "Type: %u (%s)",
377                 (u_int) hdr.rtcp_type, ptype);
378         offset++;
379
380         if (offset >= end_offset)
381                 return -1;
382         proto_tree_add_text(rtcp_tree, offset, 2, "Length / 4 - 1: %u",
383                 (unsigned) hdr.rtcp_length);
384         offset += 2;
385
386         /*
387          * Don't add 1 to length, since it's accounted for above.
388          */
389         end_packet = offset + hdr.rtcp_length * 4;
390
391         switch (hdr.rtcp_type) {
392         case RTCP_TYPE_RR:
393                 offset = dissect_rtcp_rr(&hdr, pd, offset, start_packet,
394                         end_packet, rtcp_tree);
395                 break;
396         case RTCP_TYPE_SR:
397                 offset = dissect_rtcp_sr(&hdr, pd, offset, start_packet,
398                         end_packet, rtcp_tree);
399                 break;
400         case RTCP_TYPE_SDES:
401                 offset = dissect_rtcp_sdes(&hdr, pd, offset, start_packet,
402                         end_packet, rtcp_tree);
403                 break;
404         default:
405                 proto_tree_add_text(rtcp_tree, offset, END_OF_FRAME,
406                         "TYPE NOT HANDLED YET");
407                 offset = end_packet;
408                 break;
409         }
410
411         if (offset > 0 && offset < end_packet) {
412                 proto_tree_add_text(rtcp_tree, offset, end_packet - offset,
413                         "Extra data (%d bytes)", end_packet - offset);
414         }
415         if (offset < 0)
416                 return offset;
417         return end_packet;
418 }
419
420 void
421 dissect_rtcp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
422 {
423         int             end_offset;
424
425         if (check_col(fd, COL_PROTOCOL))
426                 col_add_str(fd, COL_PROTOCOL, "RTCP");
427
428         if (!tree)
429                 return;
430
431         end_offset = offset + END_OF_FRAME;
432         while (offset > 0 && offset < end_offset) {
433                 offset = dissect_one_rtcp(pd, offset, fd, tree);
434         }
435         if (offset < 0) {
436                 proto_tree_add_text(tree, end_offset, 0,
437                         "Unexpected end of packet");
438         }
439 }
440
441 void
442 proto_register_rtcp(void)
443 {
444 /*        static hf_register_info hf[] = {
445                 { &variable,
446                 { "Name",           "rtcp.abbreviation", TYPE, VALS_POINTER }},
447         };*/
448         static gint *ett[] = {
449                 &ett_rtcp,
450         };
451
452         proto_rtcp = proto_register_protocol("RTP Control Protocol", "rtcp");
453  /*       proto_register_field_array(proto_rtcp, hf, array_length(hf));*/
454         proto_register_subtree_array(ett, array_length(ett));
455 }