Move format_text(), get_token_len(), and fine_line_end(), into strutil.c
[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.5 2000/09/11 16:16:02 gram 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 #include "strutil.h"
47
48 static int proto_rtcp = -1;
49
50 static gint ett_rtcp = -1;
51
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)
57
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 */
63
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 */
68 } rtcp_hdr_t;
69
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 */
79 } rtcp_report_t;
80
81 static int
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)
84 {
85         int             end_offset = offset + END_OF_FRAME;
86         rtcp_report_t   rep;
87
88         if (offset >= end_offset)
89                 return -1;
90
91         memcpy(&rep, &pd[offset], sizeof(rtcp_report_t) <= END_OF_FRAME ?
92                 sizeof(rtcp_report_t) : END_OF_FRAME);
93
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);
100
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");
105         }
106
107         proto_tree_add_text(rtcp_tree, NullTVB, offset, 4,
108                 "Source %d SSRC: %u", sn + 1, rep.rtcp_rr_ssrc);
109         offset += 4;
110
111         proto_tree_add_text(rtcp_tree, NullTVB, offset, 1,
112                 "Fraction lost: %u / 256", (unsigned) rep.rtcp_rr_flt);
113         offset += 1;
114
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);
119         offset += 3;
120
121         proto_tree_add_text(rtcp_tree, NullTVB, offset, 4,
122                 "Extended Highest Seq #: %lu",
123                 (unsigned long) rep.rtcp_rr_xhiseq);
124         offset += 4;
125
126         proto_tree_add_text(rtcp_tree, NullTVB, offset, 4,
127                 "Jitter: %lu", (unsigned long) rep.rtcp_rr_jitter);
128         offset += 4;
129
130         proto_tree_add_text(rtcp_tree, NullTVB, offset, 4,
131                 "Last SR timestamp (middle): %lu",
132                 (unsigned long) rep.rtcp_rr_lsr);
133         offset += 4;
134
135         proto_tree_add_text(rtcp_tree, NullTVB, offset, 4,
136                 "Delay Since Last SR: %lu",
137                 (unsigned long) rep.rtcp_rr_dlsr);
138         offset += 4;
139
140         return offset;
141 }
142
143 typedef struct rtcp_rr {
144         guint32 rtcp_rr_ssrc;
145 } rtcp_rr_t;
146
147 static int
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)
150 {
151         int             end_offset = offset + END_OF_FRAME; 
152         rtcp_rr_t       rr;
153         int             sn;
154
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);
158
159         if ((offset + sizeof(rtcp_rr_t)) >= end_offset)
160                 return -1;
161         proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, "Sender SSRC: %u",
162                 rr.rtcp_rr_ssrc);
163         offset += 4;
164
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);
168         }
169
170         return offset;
171 }
172
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 */
180 } rtcp_sr_t;
181
182 static int
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)
185 {
186         int             end_offset = offset + END_OF_FRAME; 
187         rtcp_sr_t       sr;
188         int             sn;
189
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);
198
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");
203         }
204
205         proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, "Sender's SSRC: %u",
206                 sr.rtcp_sr_ssrc);
207         offset += 4;
208         proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, "NTP timestamp, MSW: %u",
209                 sr.rtcp_sr_ntp_hi);
210         offset += 4;
211         proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, "NTP timestamp, LSW: %u",
212                 sr.rtcp_sr_ntp_lo);
213         offset += 4;
214         proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, "RTP timestamp: %u",
215                 sr.rtcp_sr_rtp_time);
216         offset += 4;
217         proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, "Sender's packet count: %u",
218                 sr.rtcp_sr_npackets);
219         offset += 4;
220         proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, "Sender's octet count: %u",
221                 sr.rtcp_sr_nbytes);
222         offset += 4;
223
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);
227         }
228
229         return offset;
230 }
231
232 static struct rtcp_chunk_type {
233         int             type;
234         const char      *name;
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)" },
244         { 0, 0 }
245 };
246
247 static struct rtcp_chunk_type *
248 rtcp_find_chunk_type(int type)
249 {
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)
254                         return tt;
255         }
256         return &unk;
257 }
258
259 static int
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)
262 {
263         unsigned        type;
264         unsigned        len;
265         struct rtcp_chunk_type *ctype;
266
267         if ((offset + 4) > end_packet)
268                 return -1;
269         proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, "Chunk %d SSRC: %u",
270                 cn + 1, pntohl(&pd[offset]));
271         offset += 4;
272
273         for (;;) {
274                 if ((offset + 1) > end_packet)
275                         return -1;
276
277                 type = pd[offset];
278                 if (type == 0) {
279                         int pad_start = offset;
280                         offset++;
281                         /* NULL terminator -- align to next 32 bit boundary */
282                         if ((offset - start_packet) & 3) {
283                                 offset += 4 - ((offset - start_packet) & 3);
284                         }
285                         proto_tree_add_text(rtcp_tree, NullTVB, pad_start,
286                                 offset - pad_start,
287                                 "(end of chunk and alignment padding)");
288                         break;
289                 }
290
291                 ctype = rtcp_find_chunk_type(type);
292
293                 proto_tree_add_text(rtcp_tree, NullTVB, offset, 1, "Chunk type: %s",
294                         ctype->name);
295                 offset++;
296
297                 if ((offset + 1) > end_packet)
298                         return -1;
299
300                 len = pd[offset];
301                 proto_tree_add_text(rtcp_tree, NullTVB, offset, 1, "Chunk length: %u",
302                         (unsigned) len);
303                 offset++;
304
305                 if ((offset + len) > end_packet)
306                         return -1;
307
308                 proto_tree_add_text(rtcp_tree, NullTVB, offset, len, "Chunk string: %s",
309                         format_text(&pd[offset], len));
310                 offset += len;
311         }
312         return offset;
313 }
314
315 static int
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)
318 {
319         int             cn;
320
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);
324         }
325         return offset;
326 }
327
328 static int
329 dissect_one_rtcp(const u_char *pd, int offset, frame_data *fd,
330         proto_tree *tree)
331 {
332         proto_tree      *rtcp_tree;
333         proto_item      *ti;
334         const u_char    *data, *dataend;
335         int             end_offset;
336         int             start_packet;
337         int             end_packet;
338         rtcp_hdr_t      hdr;
339         const char      *ptype;
340
341         data = &pd[offset];
342         dataend = data + END_OF_FRAME;
343         start_packet = offset;
344         end_offset = offset + END_OF_FRAME;
345
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);
348
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);
352
353         if (offset >= end_offset)
354                 return -1;
355         proto_tree_add_text(rtcp_tree, NullTVB, offset, 1, "Version: %u (%s)",
356                 RTCP_VERSION(&hdr),
357                 RTCP_VERSION(&hdr) == 3 ? "New Unknown Version" :
358                 RTCP_VERSION(&hdr) == 2 ? "RFC 1889 Version" :
359                 RTCP_VERSION(&hdr) == 1 ? "First Draft Version" :
360                 "Old Vat Version");
361         proto_tree_add_text(rtcp_tree, NullTVB, offset, 1, "Padding: %u",
362                 RTCP_PADDING(&hdr));
363         proto_tree_add_text(rtcp_tree, NullTVB, offset, 1, "Count: %u",
364                 RTCP_COUNT(&hdr));
365         offset++;
366
367         if (offset >= end_offset)
368                 return -1;
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;
376         }
377         proto_tree_add_text(rtcp_tree, NullTVB, offset, 1, "Type: %u (%s)",
378                 (u_int) hdr.rtcp_type, ptype);
379         offset++;
380
381         if (offset >= end_offset)
382                 return -1;
383         proto_tree_add_text(rtcp_tree, NullTVB, offset, 2, "Length / 4 - 1: %u",
384                 (unsigned) hdr.rtcp_length);
385         offset += 2;
386
387         /*
388          * Don't add 1 to length, since it's accounted for above.
389          */
390         end_packet = offset + hdr.rtcp_length * 4;
391
392         switch (hdr.rtcp_type) {
393         case RTCP_TYPE_RR:
394                 offset = dissect_rtcp_rr(&hdr, pd, offset, start_packet,
395                         end_packet, rtcp_tree);
396                 break;
397         case RTCP_TYPE_SR:
398                 offset = dissect_rtcp_sr(&hdr, pd, offset, start_packet,
399                         end_packet, rtcp_tree);
400                 break;
401         case RTCP_TYPE_SDES:
402                 offset = dissect_rtcp_sdes(&hdr, pd, offset, start_packet,
403                         end_packet, rtcp_tree);
404                 break;
405         default:
406                 proto_tree_add_text(rtcp_tree, NullTVB, offset, END_OF_FRAME,
407                         "TYPE NOT HANDLED YET");
408                 offset = end_packet;
409                 break;
410         }
411
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);
415         }
416         if (offset < 0)
417                 return offset;
418         return end_packet;
419 }
420
421 void
422 dissect_rtcp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
423 {
424         int             end_offset;
425
426         OLD_CHECK_DISPLAY_AS_DATA(proto_rtcp, pd, offset, fd, tree);
427
428         if (check_col(fd, COL_PROTOCOL))
429                 col_add_str(fd, COL_PROTOCOL, "RTCP");
430
431         if (!tree)
432                 return;
433
434         end_offset = offset + END_OF_FRAME;
435         while (offset > 0 && offset < end_offset) {
436                 offset = dissect_one_rtcp(pd, offset, fd, tree);
437         }
438         if (offset < 0) {
439                 proto_tree_add_text(tree, NullTVB, end_offset, 0,
440                         "Unexpected end of packet");
441         }
442 }
443
444 void
445 proto_register_rtcp(void)
446 {
447 /*        static hf_register_info hf[] = {
448                 { &variable,
449                 { "Name",           "rtcp.abbreviation", TYPE, VALS_POINTER }},
450         };*/
451         static gint *ett[] = {
452                 &ett_rtcp,
453         };
454
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));
458 }