From d47704c82b35c8e28df3ba60e0acd4f1b8390f7f Mon Sep 17 00:00:00 2001 From: guy Date: Thu, 19 Oct 2000 06:45:11 +0000 Subject: Andreas Sikkema's new H.261 and TPKT dissectors, replacement RTCP and RTP dissectors, and changes to the Q.931 dissector for use with H.323. git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@2511 f5534014-38df-0310-8fa8-9805f1628bb7 --- AUTHORS | 11 +- Makefile.am | 6 +- Makefile.nmake | 4 +- packet-h261.c | 262 +++++++++++ packet-h261.h | 30 ++ packet-q931.c | 369 ++++++++++++--- packet-rtcp.c | 1427 ++++++++++++++++++++++++++++++++++++++++++-------------- packet-rtcp.h | 19 +- packet-rtp.c | 708 ++++++++++++++++++++++------ packet-rtp.h | 19 +- packet-rtsp.c | 6 +- packet-tpkt.c | 187 ++++++++ packet-tpkt.h | 30 ++ 13 files changed, 2490 insertions(+), 588 deletions(-) create mode 100644 packet-h261.c create mode 100644 packet-h261.h create mode 100644 packet-tpkt.c create mode 100644 packet-tpkt.h diff --git a/AUTHORS b/AUTHORS index 9c5a06465b..d74cb0f777 100644 --- a/AUTHORS +++ b/AUTHORS @@ -124,7 +124,7 @@ Aaron Hillegass { } Jason Lango { - RTSP, SDP, RTCP, RTP + RTSP, SDP } Johan Feyaerts { @@ -203,7 +203,7 @@ Heikki Vatiainen { VRRP (Virtual Router Redundancy) HSRP (Hot Standby Router Protocol) option to control whether to interpret the IPv4 TOS field as - such or as the DiffServ field + such or as the DiffServ field COPS } @@ -295,6 +295,7 @@ Doug Nazar { Andreas Sikkema { Fixes to SMB dissector Fixes to capture file handling on Win32 + RTCP, RTP, TPKT (RFC 1006), H.261 } Mark Muhlestein { @@ -307,10 +308,10 @@ Graham Bloice { Support for sorting columns in the summary by clicking on them Win32 Makefile improvements Support for "Update list of packets in real time" during capture - on Win32 + on Win32 Support for inverse video rather than boldface highlighting of - the bytes, in the hex dump window, corresponding to a selected - field + the bytes, in the hex dump window, corresponding to a selected + field } Ralf Schneider { diff --git a/Makefile.am b/Makefile.am index 871f2dbef7..b7a3afe7de 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ # Makefile.am # Automake file for Ethereal # -# $Id: Makefile.am,v 1.235 2000/10/14 05:11:11 gram Exp $ +# $Id: Makefile.am,v 1.236 2000/10/19 06:45:10 guy Exp $ # # Ethereal - Network traffic analyzer # By Gerald Combs @@ -63,6 +63,7 @@ DISSECTOR_SOURCES = \ packet-giop.c \ packet-gre.c \ packet-h1.c \ + packet-h261.c \ packet-hsrp.c \ packet-http.c \ packet-icmpv6.c\ @@ -151,6 +152,7 @@ DISSECTOR_SOURCES = \ packet-tftp.c \ packet-time.c \ packet-tns.c \ + packet-tpkt.c \ packet-tr.c \ packet-trmac.c \ packet-udp.c \ @@ -190,6 +192,7 @@ noinst_HEADERS = \ packet-eth.h \ packet-fddi.h \ packet-frame.h \ + packet-h261.h \ packet-http.h \ packet-ip.h \ packet-ipp.h \ @@ -239,6 +242,7 @@ noinst_HEADERS = \ packet-tcp.h \ packet-tftp.h \ packet-tns.h \ + packet-tpkt.h \ packet-tr.h \ packet-trmac.h \ packet-udp.h \ diff --git a/Makefile.nmake b/Makefile.nmake index a8dbda8b54..5824652d74 100644 --- a/Makefile.nmake +++ b/Makefile.nmake @@ -1,7 +1,7 @@ ## Makefile for building ethereal.exe with Microsoft C and nmake ## Use: nmake -f makefile.nmake # -# $Id: Makefile.nmake,v 1.58 2000/10/14 04:31:24 gram Exp $ +# $Id: Makefile.nmake,v 1.59 2000/10/19 06:45:10 guy Exp $ include config.nmake @@ -51,6 +51,7 @@ DISSECTOR_SOURCES = \ packet-giop.c \ packet-gre.c \ packet-h1.c \ + packet-h261.c \ packet-hsrp.c \ packet-http.c \ packet-icmpv6.c\ @@ -139,6 +140,7 @@ DISSECTOR_SOURCES = \ packet-tftp.c \ packet-time.c \ packet-tns.c \ + packet-tpkt.c \ packet-tr.c \ packet-trmac.c \ packet-udp.c \ diff --git a/packet-h261.c b/packet-h261.c new file mode 100644 index 0000000000..8bcbde1291 --- /dev/null +++ b/packet-h261.c @@ -0,0 +1,262 @@ +/* packet-h261.c + * + * Routines for ITU-T Recommendation H.261 dissection + * + * Copyright 2000, Philips Electronics N.V. + * Andreas Sikkema + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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 H261 protocol according to Annex C + * of ITU-T Recommendation H.225.0 (02/98) + * + * This dissector is called by the RTP dissector + */ + + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include "packet.h" + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#include +#include + +#include "packet-h261.h" + +/* H261 header fields */ +static int proto_h261 = -1; +static int hf_h261_sbit = -1; +static int hf_h261_ebit = -1; +static int hf_h261_ibit = -1; +static int hf_h261_vbit = -1; +static int hf_h261_gobn = -1; +static int hf_h261_mbap = -1; +static int hf_h261_quant = -1; +static int hf_h261_hmvd = -1; /* Mislabeled in a figure in section C.3.1 as HMDV */ +static int hf_h261_vmvd = -1; +static int hf_h261_data = -1; + +/* H261 fields defining a sub tree */ +static gint ett_h261 = -1; + +void +dissect_h261( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree ) +{ + proto_item *ti = NULL; + proto_tree *h261_tree = NULL; + unsigned int offset = 0; + + if ( check_col( pinfo->fd, COL_PROTOCOL ) ) { + col_add_str( pinfo->fd, COL_PROTOCOL, "H261" ); + } + + if ( check_col( pinfo->fd, COL_INFO) ) { + col_add_str( pinfo->fd, COL_INFO, "H.261 message"); + } + + if ( tree ) { + /* Using fd->pkt_len here instead of END_OF_FRAME. This variable is changed in dissect_rtp()! */ + ti = proto_tree_add_item( tree, proto_h261, tvb, offset, tvb_length( tvb ), FALSE ); + h261_tree = proto_item_add_subtree( ti, ett_h261 ); + /* SBIT 1st octet, 3 bits */ + proto_tree_add_uint( h261_tree, hf_h261_sbit, tvb, offset, 1, tvb_get_guint8( tvb, offset ) >> 5 ); + /* EBIT 1st octet, 3 bits */ + proto_tree_add_item( h261_tree, hf_h261_ebit, tvb, offset, 1, ( tvb_get_guint8( tvb, offset ) << 3 ) >> 5 ); + /* I flag, 1 bit */ + proto_tree_add_boolean( h261_tree, hf_h261_ibit, tvb, offset, 1, tvb_get_guint8( tvb, offset ) & 2 ); + /* V flag, 1 bit */ + proto_tree_add_boolean( h261_tree, hf_h261_vbit, tvb, offset, 1, tvb_get_guint8( tvb, offset ) & 1 ); + offset++; + + /* GOBN 2nd octet, 4 bits */ + proto_tree_add_uint( h261_tree, hf_h261_gobn, tvb, offset, 1, tvb_get_guint8( tvb, offset ) >> 4 ); + /* MBAP 2nd octet, 4 bits, 3rd octet 1 bit */ + proto_tree_add_uint( h261_tree, hf_h261_mbap, tvb, offset, 1, + ( tvb_get_guint8( tvb, offset ) & 15 ) + + ( tvb_get_guint8( tvb, offset + 1 ) >> 7 ) ); + offset++; + + /* QUANT 3rd octet, 5 bits (starting at bit 2!) */ + proto_tree_add_uint( h261_tree, hf_h261_mbap, tvb, offset, 1, tvb_get_guint8( tvb, offset ) & 124 ); + /* HMDV 3rd octet 2 bits, 4th octet 3 bits */ + proto_tree_add_uint( h261_tree, hf_h261_mbap, tvb, offset, 1, + ( ( tvb_get_guint8( tvb, offset ) << 4) >> 4 ) + + ( tvb_get_guint8( tvb, offset ) >> 5 ) ); + offset++; + + /* VMVD 4th octet, last 5 bits */ + proto_tree_add_uint( h261_tree, hf_h261_mbap, tvb, offset, 1, tvb_get_guint8( tvb, offset ) & 31 ); + offset++; + + /* The rest of the packet is the H.261 stream */ + proto_tree_add_bytes( h261_tree, hf_h261_data, tvb, offset, tvb_length_remaining( tvb, offset ), tvb_get_ptr( tvb, offset, tvb_length_remaining( tvb, offset ) ) ); + } +} + +void +proto_register_h261(void) +{ + static hf_register_info hf[] = + { + { + &hf_h261_sbit, + { + "Start bit position", + "h261.sbit", + FT_UINT8, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_h261_ebit, + { + "End bit position", + "h261.ebit", + FT_UINT8, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_h261_ibit, + { + "Intra frame encoded data flag", + "h261.i", + FT_BOOLEAN, + BASE_NONE, + NULL, + 0x0, + "" + } + }, + { + &hf_h261_vbit, + { + "Motion vector flag", + "h261.v", + FT_BOOLEAN, + BASE_NONE, + NULL, + 0x0, + "" + } + }, + { + &hf_h261_gobn, + { + "GOB Number", + "h261.gobn", + FT_UINT8, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_h261_mbap, + { + "Macroblock address predictor", + "h261.mbap", + FT_UINT8, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_h261_quant, + { + "Quantizer", + "h261.quant", + FT_UINT8, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_h261_hmvd, + { + "Horizontal motion vctor data", + "h261.hmvd", + FT_UINT8, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_h261_vmvd, + { + "Vertical motion vector data", + "h261.vmvd", + FT_UINT8, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_h261_data, + { + "H.261 stream", + "h261.stream", + FT_BYTES, + BASE_NONE, + NULL, + 0x0, + "" + } + }, +}; + + static gint *ett[] = + { + &ett_h261, + }; + + + proto_h261 = proto_register_protocol("ITU-T Recommendation H.261", "h261"); + proto_register_field_array(proto_h261, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); +} diff --git a/packet-h261.h b/packet-h261.h new file mode 100644 index 0000000000..ad29d8ee32 --- /dev/null +++ b/packet-h261.h @@ -0,0 +1,30 @@ +/* packet-h261.h + * + * Routines for ITU-T Recommendation H.261 dissection + * + * Copyright 2000, Philips Electronics N.V. + * Andreas Sikkema + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + + +void dissect_h261( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree ); +void proto_register_h261( void ); diff --git a/packet-q931.c b/packet-q931.c index 1317b85d03..76bf16d54e 100644 --- a/packet-q931.c +++ b/packet-q931.c @@ -2,7 +2,9 @@ * Routines for Q.931 frame disassembly * Guy Harris * - * $Id: packet-q931.c,v 1.17 2000/08/13 14:08:38 deniel Exp $ + * $Id: packet-q931.c,v 1.18 2000/10/19 06:45:10 guy Exp $ + * + * Modified by Andreas Sikkema for possible use with H.323 * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -39,6 +41,11 @@ #include "nlpid.h" #include "packet-q931.h" +#ifdef H323 +#include "packet-tpkt.h" +#include "packet-h225.h" +#endif + /* Q.931 references: * * http://www.acacia-net.com/Clarinet/Protocol/q9313svn.htm @@ -63,6 +70,7 @@ static gint ett_q931_ie = -1; /* * Q.931 message types. */ +#define Q931_ESCAPE 0x00 #define Q931_ALERTING 0x01 #define Q931_CALL_PROCEEDING 0x02 #define Q931_CONNECT 0x07 @@ -98,6 +106,7 @@ static gint ett_q931_ie = -1; #define Q931_STATUS_ENQUIRY 0x75 static const value_string q931_message_type_vals[] = { + { Q931_ESCAPE, "ESCAPE" }, { Q931_ALERTING, "ALERTING" }, { Q931_CALL_PROCEEDING, "CALL PROCEEDING" }, { Q931_CONNECT, "CONNECT" }, @@ -506,6 +515,46 @@ static const value_string q931_uil3_vals[] = { { 0, NULL } }; +/* + * XXX - should this (or, rather, a routine to return a string containing + * the stuff we put after "Protocol discriminator:") be in "packet-osi.c"? + * + * I.e., is the convention that 16-63 and 80-254 are for network-layer + * or layer-3 protocols, and 64-79 are for national use, specific to + * Q.931 (and maybe Q.2931), or is it a more general ISO standard? + */ +static void +dissect_q931_protocol_discriminator(tvbuff_t *tvb, int offset, proto_tree *tree) +{ + unsigned int discriminator = tvb_get_guint8(tvb, offset); + char *nlpid_string; + + nlpid_string = match_strval(discriminator, nlpid_vals); + if (nlpid_string != NULL) { + proto_tree_add_uint_format(tree, hf_q931_discriminator, + tvb, offset, 1, discriminator, + "Protocol discriminator: %s", nlpid_string); + } else { + if ((discriminator >= 16 && discriminator < 63) + || ((discriminator >= 80) && (discriminator < 254))) { + proto_tree_add_uint_format(tree, hf_q931_discriminator, + tvb, offset, 1, discriminator, + "Protocol discriminator: Network layer or layer 3 protocol (0x%02X)", + discriminator); + } else if (discriminator >= 64 && discriminator <= 79) { + proto_tree_add_uint_format(tree, hf_q931_discriminator, + tvb, offset, 1, discriminator, + "Protocol discriminator: National use (0x%02X)", + discriminator); + } else { + proto_tree_add_uint_format(tree, hf_q931_discriminator, + tvb, offset, 1, discriminator, + "Protocol discriminator: Reserved (0x%02X)", + discriminator); + } + } +} + void dissect_q931_bearer_capability_ie(tvbuff_t *tvb, int offset, int len, proto_tree *tree) @@ -699,7 +748,7 @@ dissect_q931_bearer_capability_ie(tvbuff_t *tvb, int offset, int len, proto_tree_add_text(tree, tvb, offset, 1, "Modem type: %s", val_to_str(modem_type, q931_l1_modem_type_vals, - NULL)); + "Unknown (0x%02X)")); } offset += 1; len -= 1; @@ -1004,7 +1053,7 @@ dissect_q931_cause_ie(tvbuff_t *tvb, int offset, int len, proto_tree_add_text(tree, tvb, offset, 1, "Recommendation: %s", val_to_str(octet & 0x7F, q931_cause_recommendation_vals, - "Unknown (0x%X)")); + "Unknown (0x%02X)")); offset += 1; len -= 1; } @@ -1015,7 +1064,7 @@ dissect_q931_cause_ie(tvbuff_t *tvb, int offset, int len, proto_tree_add_text(tree, tvb, offset, 1, "Cause value: %s", val_to_str(octet & 0x7F, q931_cause_code_vals, - "Unknown (0x%X)")); + "Unknown (0x%02X)")); offset += 1; len -= 1; @@ -1148,7 +1197,7 @@ dissect_q931_channel_identification_ie(tvbuff_t *tvb, int offset, int len, proto_tree_add_text(tree, tvb, offset, 1, "Channel selection: %s", val_to_str(octet & 0x03, q931_not_basic_channel_selection_vals, - NULL)); + "Unknown (0x%X)")); } else { proto_tree_add_text(tree, tvb, offset, 1, "Channel selection: %s", @@ -1210,7 +1259,7 @@ dissect_q931_channel_identification_ie(tvbuff_t *tvb, int offset, int len, "%s type: %s", (octet & Q931_IS_SLOT_MAP) ? "Map element" : "Channel", val_to_str(octet & 0x0F, q931_element_type_vals, - "Unknown (0x%02X)")); + "Unknown (0x%02X)")); /* * XXX - dump the channel number or slot map. @@ -1327,9 +1376,8 @@ dissect_q931_ns_facilities_ie(tvbuff_t *tvb, int offset, int len, netid_len = len; if (netid_len != 0) { proto_tree_add_text(tree, tvb, offset, netid_len, - "Network identification: %.*s", - netid_len, - tvb_get_ptr(tvb, offset, netid_len)); + "Network identification: %s", + tvb_format_text(tvb, offset, netid_len)); offset += netid_len; len -= netid_len; } @@ -1431,7 +1479,8 @@ dissect_q931_signal_ie(tvbuff_t *tvb, int offset, int len, } proto_tree_add_text(tree, tvb, offset, 1, "Signal: %s", - val_to_str(tvb_get_guint8(tvb, offset), q931_signal_vals, "Unknown (0x%02X)")); + val_to_str(tvb_get_guint8(tvb, offset), q931_signal_vals, + "Unknown (0x%02X)")); } /* @@ -1463,20 +1512,20 @@ dissect_q931_information_rate_ie(tvbuff_t *tvb, int offset, int len, } proto_tree_add_text(tree, tvb, offset + 0, 1, "Incoming information rate: %s", - val_to_str(tvb_get_guint8(tvb, offset + 0) & 0x1F, q931_throughput_class_vals, - "Unknown (0x%02X)")); + val_to_str(tvb_get_guint8(tvb, offset + 0) & 0x1F, + q931_throughput_class_vals, "Unknown (0x%02X)")); proto_tree_add_text(tree, tvb, offset + 1, 1, "Outgoing information rate: %s", - val_to_str(tvb_get_guint8(tvb, offset + 1) & 0x1F, q931_throughput_class_vals, - "Unknown (0x%02X)")); + val_to_str(tvb_get_guint8(tvb, offset + 1) & 0x1F, + q931_throughput_class_vals, "Unknown (0x%02X)")); proto_tree_add_text(tree, tvb, offset + 2, 1, "Minimum incoming information rate: %s", - val_to_str(tvb_get_guint8(tvb, offset + 2) & 0x1F, q931_throughput_class_vals, - "Unknown (0x%02X)")); + val_to_str(tvb_get_guint8(tvb, offset + 2) & 0x1F, + q931_throughput_class_vals, "Unknown (0x%02X)")); proto_tree_add_text(tree, tvb, offset + 3, 1, "Minimum outgoing information rate: %s", - val_to_str(tvb_get_guint8(tvb, offset + 3) & 0x1F, q931_throughput_class_vals, - "Unknown (0x%02X)")); + val_to_str(tvb_get_guint8(tvb, offset + 3) & 0x1F, + q931_throughput_class_vals, "Unknown (0x%02X)")); } static int @@ -1620,8 +1669,7 @@ dissect_q931_pl_binary_parameters_ie(tvbuff_t *tvb, int offset, int len, octet = tvb_get_guint8(tvb, offset); proto_tree_add_text(tree, tvb, offset, 1, "Fast select: %s", - val_to_str(octet & 0x18, q931_fast_selected_vals, - NULL)); + val_to_str(octet & 0x18, q931_fast_selected_vals, NULL)); proto_tree_add_text(tree, tvb, offset, 1, "%s", (octet & 0x04) ? "No request/request denied" : @@ -1690,15 +1738,15 @@ dissect_q931_cug_ie(tvbuff_t *tvb, int offset, int len, proto_tree *tree) return; proto_tree_add_text(tree, tvb, offset, 1, "CUG indication: %s", - val_to_str(tvb_get_guint8(tvb, offset) & 0x07, q931_cug_indication_vals, - "Unknown (0x%02X)")); + val_to_str(tvb_get_guint8(tvb, offset) & 0x07, + q931_cug_indication_vals, "Unknown (0x%02X)")); offset += 1; len -= 1; if (len == 0) return; - proto_tree_add_text(tree, tvb, offset, len, "CUG index code: %.*s", len, - tvb_get_ptr(tvb, offset, len)); + proto_tree_add_text(tree, tvb, offset, len, "CUG index code: %s", + tvb_format_text(tvb, offset, len)); } /* @@ -1717,8 +1765,8 @@ dissect_q931_reverse_charge_ind_ie(tvbuff_t *tvb, int offset, int len, return; proto_tree_add_text(tree, tvb, offset, 1, "Reverse charging indication: %s", - val_to_str(tvb_get_guint8(tvb, offset) & 0x07, q931_reverse_charging_indication_vals, - "Unknown (0x%02X)")); + val_to_str(tvb_get_guint8(tvb, offset) & 0x07, + q931_reverse_charging_indication_vals, "Unknown (0x%02X)")); } /* @@ -1823,8 +1871,8 @@ dissect_q931_number_ie(tvbuff_t *tvb, int offset, int len, if (len == 0) return; - proto_tree_add_text(tree, tvb, offset, len, "Number: %.*s", - len, tvb_get_ptr(tvb, offset, len)); + proto_tree_add_text(tree, tvb, offset, len, "Number: %s", + tvb_format_text(tvb, offset, len)); } /* @@ -1889,8 +1937,8 @@ dissect_q931_restart_indicator_ie(tvbuff_t *tvb, int offset, int len, } proto_tree_add_text(tree, tvb, offset, 1, "Restart indicator: %s", - val_to_str(tvb_get_guint8(tvb, offset) & 0x07, q931_restart_indicator_class_vals, - "Unknown (0x%02X)")); + val_to_str(tvb_get_guint8(tvb, offset) & 0x07, + q931_restart_indicator_class_vals, "Unknown (0x%02X)")); } /* @@ -1958,7 +2006,7 @@ dissect_q931_high_layer_compat_ie(tvbuff_t *tvb, int offset, int len, proto_tree_add_text(tree, tvb, offset, 1, "High layer characteristics identification: %s", val_to_str(characteristics, q931_high_layer_characteristics_vals, - NULL)); + "Unknown (0x%02X)")); offset += 1; len -= 1; @@ -1969,13 +2017,15 @@ dissect_q931_high_layer_compat_ie(tvbuff_t *tvb, int offset, int len, if (characteristics == Q931_AUDIOVISUAL) { proto_tree_add_text(tree, tvb, offset, 1, "Extended audiovisual characteristics identification: %s", - val_to_str(octet & 0x7F, q931_audiovisual_characteristics_vals, - NULL)); + val_to_str(octet & 0x7F, + q931_audiovisual_characteristics_vals, + "Unknown (0x%02X)")); } else { proto_tree_add_text(tree, tvb, offset, 1, "Extended high layer characteristics identification: %s", - val_to_str(octet & 0x7F, q931_high_layer_characteristics_vals, - NULL)); + val_to_str(octet & 0x7F, + q931_high_layer_characteristics_vals, + "Unknown (0x%02X)")); } } } @@ -2018,8 +2068,8 @@ dissect_q931_user_user_ie(tvbuff_t *tvb, int offset, int len, switch (octet) { case Q931_PROTOCOL_DISCRIMINATOR_IA5: - proto_tree_add_text(tree, tvb, offset, len, "User information: %.*s", - len, tvb_get_ptr(tvb, offset, len)); + proto_tree_add_text(tree, tvb, offset, len, "User information: %s", + tvb_format_text(tvb, offset, len)); break; default: @@ -2037,8 +2087,8 @@ dissect_q931_ia5_ie(tvbuff_t *tvb, int offset, int len, proto_tree *tree, char *label) { if (len != 0) { - proto_tree_add_text(tree, tvb, offset, len, "%s: %.*s", label, len, - tvb_get_ptr(tvb, offset, len)); + proto_tree_add_text(tree, tvb, offset, len, "%s: %s", label, + tvb_format_text(tvb, offset, len)); } } @@ -2051,8 +2101,9 @@ static const value_string q931_codeset_vals[] = { { 0x00, NULL }, }; -void -dissect_q931(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +static gboolean +q931_dissector(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + gboolean started_heuristic) { int offset = 0; guint reported_length; @@ -2063,13 +2114,107 @@ dissect_q931(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) guint8 call_ref[15]; guint8 message_type; guint8 info_element; - guint8 info_element_len; - int codeset; + guint16 info_element_len; + int codeset; gboolean non_locking_shift; + guint8 protocol_discriminator; - CHECK_DISPLAY_AS_DATA(proto_q931, tvb, pinfo, tree); +#ifdef H323 + tvbuff_t *h225_tvb; + gboolean is_h323_h225 = FALSE; + /* + * It is very much possible to find a TPKT header here + * TPKT is defined in RFC 1009 as a wrapper around ISO + * defined protocols. There could even be several TPKT + * wrapped messages in one TCP data field... + * XXXXXXXX THIS IS NOT IMPLEMENTED YET!!! XXXXXXXXXXX + * + * For Q.931 related messages this is easy. If a + * protocol discriminator is found with a value of 3 + * and it's the first discriminator in the Q.931 + * message one can safely assume it to be a TPKT + * header. See also Q.931 Table 4-1/Q.931 + */ +#endif - pinfo->current_proto = "Q.931"; + protocol_discriminator = tvb_get_guint8( tvb, offset ); + /* Keep the protocol discriminator for later use */ + +#ifdef H323 + if ( started_heuristic ) { + /* + * The heuristic Q.931 message should conform to this + */ + if ( protocol_discriminator != NLPID_Q_931 ) + return FALSE; + + if ( ! is_tpkt( tvb, &offset ) ) + return FALSE; + + if ( tvb_length_remaining( tvb, offset ) <= 3 ) + return FALSE; + } + + /* + * The first byte should be < 8 (3 is TPKT, rest is Q.931) + */ + if ( protocol_discriminator < 8 ) { + /* + * The minimum length of a Q.931 message is 3: + * 1 byte for the protocol discriminator, + * 1 for the call_reference length, + * and one for the message type. + */ + if ( tvb_length_remaining( tvb, offset ) <= 3 ) + return FALSE; + + /* + * OK, there are a couple of bytes available, but is there + * also a protocol discriminator? + */ + if ( tvb_length_remaining( tvb, offset ) > 3 ) { + /* Reread the protocol discriminator */ + protocol_discriminator = + tvb_get_guint8( tvb, offset + 4); + } else { + /* No discriminator available */ + protocol_discriminator = 0; + } + + /* + * If it's not H.323 related Q.931 no heuristic action needed + * Dangerous, there might be other uses for this code..... + */ + if ( ( started_heuristic ) && (protocol_discriminator != 8 ) ) + return FALSE; + + /* + * Always check if it's a real TPKT message + */ + if ( ! is_tpkt( tvb, &offset ) ) + return FALSE; + + dissect_tpkt( tvb, &offset, pinfo, tree ); + + /* + * Reset the current_proto variable because dissect_tpkt + * messed with it + */ + if ( started_heuristic ) + pinfo->current_proto = "Q.931 HEUR"; + else + pinfo->current_proto = "Q.931"; + } +#endif + + /* + * The minimum length of a Q.931 message is + * 3, 1 byte for the protocol discr. 1 for the call_reference length, + * and one for the message type. + */ + if ( tvb_length_remaining( tvb, offset ) <= 3 ) { + return FALSE; + } if (check_col(pinfo->fd, COL_PROTOCOL)) col_add_str(pinfo->fd, COL_PROTOCOL, "Q.931"); @@ -2079,7 +2224,7 @@ dissect_q931(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) tvb_length(tvb), FALSE); q931_tree = proto_item_add_subtree(ti, ett_q931); - proto_tree_add_uint(q931_tree, hf_q931_discriminator, tvb, offset, 1, tvb_get_guint8(tvb, offset)); + dissect_q931_protocol_discriminator( tvb, offset, q931_tree ); } offset += 1; call_ref_len = tvb_get_guint8(tvb, offset) & 0xF; /* XXX - do as a bit field? */ @@ -2195,20 +2340,72 @@ dissect_q931(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) /* * Variable-length IE. */ +#ifndef H323 info_element_len = tvb_get_guint8(tvb, offset + 1); - if (q931_tree != NULL) { - ti = proto_tree_add_text(q931_tree, tvb, offset, - 1+1+info_element_len, "%s", - val_to_str(info_element, q931_info_element_vals, - "Unknown information element (0x%02X)")); - ie_tree = proto_item_add_subtree(ti, ett_q931_ie); - proto_tree_add_text(ie_tree, tvb, offset, 1, - "Information element: %s", - val_to_str(info_element, q931_info_element_vals, - "Unknown (0x%02X)")); - proto_tree_add_text(ie_tree, tvb, offset + 1, 1, - "Length: %u", info_element_len); +#else + /* + * According to page 18 from Recommendation H.225.0 : + * " Length of user-user contents contents + * - Shall be 2 octets instead of 1 (as in Figure 4-36/Q.931)" + * + * This will be true for all messages going to / from TCP port + * 1720 and with the first and fourth octet of the user-user + * IE having the values 0x7E and 0x05 resp. + * See http://www.mbuf.org/~moto/h323/h323decoder.html + * + */ + if ( ( tvb_get_guint8( tvb, offset ) == 0x7E ) && + ( tvb_get_guint8( tvb, offset + 3 ) == 0x05 ) && + /* ( ( pi.srcport == 1720 ) || ( pi.destport == 1720 ) ) && */ + ( protocol_discriminator == NLPID_Q_931 ) ) { + info_element_len = tvb_get_ntohs( tvb, offset + 1 ); + is_h323_h225 = TRUE; + if ( tree == NULL ) { + h225_tvb = tvb_new_subset( tvb, offset + 4, info_element_len - 1, info_element_len - 1 ); + dissect_h225_cs( h225_tvb, pinfo, tree ); + /* + * Skip the 4 bytes of the element header and then the element itself + */ + offset += 4; + offset += info_element_len - 1; + } + } else { + info_element_len = tvb_get_guint8( tvb, offset + 1 ); + } +#endif + if (q931_tree != NULL) { +#ifdef H323 + if (is_h323_h225) { + ti = proto_tree_add_text(q931_tree, tvb, offset, + 1+1+1, "%s", + val_to_str(info_element, + q931_info_element_vals, + "Unknown information element (0x%02X)")); + ie_tree = proto_item_add_subtree(ti, + ett_q931_ie); + proto_tree_add_text(ie_tree, tvb, offset, 1, + "Information element: %s", + val_to_str(info_element, + q931_info_element_vals, "Unknown (0x%02X)")); + proto_tree_add_text(ie_tree, tvb, offset + 1, + 2, "Length: %u", info_element_len); + } else { +#endif + ti = proto_tree_add_text(q931_tree, tvb, offset, + 1+1+info_element_len, "%s", + val_to_str(info_element, q931_info_element_vals, + "Unknown information element (0x%02X)")); + ie_tree = proto_item_add_subtree(ti, ett_q931_ie); + proto_tree_add_text(ie_tree, tvb, offset, 1, + "Information element: %s", + val_to_str(info_element, q931_info_element_vals, + "Unknown (0x%02X)")); + proto_tree_add_text(ie_tree, tvb, offset + 1, 1, + "Length: %u", info_element_len); +#ifdef H323 + } +#endif switch (info_element) { case Q931_IE_SEGMENTED_MESSAGE: @@ -2339,8 +2536,28 @@ dissect_q931(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) break; case Q931_IE_USER_USER: - dissect_q931_user_user_ie(tvb, - offset + 2, info_element_len, ie_tree); +#ifdef H323 + if (is_h323_h225) { + h225_tvb = tvb_new_subset(tvb, + offset + 4, info_element_len - 1, + info_element_len - 1); + dissect_h225_cs(h225_tvb, pinfo, tree); + offset += 3; + proto_tree_add_text(ie_tree, tvb, + offset, 1, + "Protocol discriminator: %s", + val_to_str(tvb_get_guint8(tvb, offset), + q931_protocol_discriminator_vals, + "Unknown (0x%02x)")); + offset += info_element_len; + } else { +#endif + dissect_q931_user_user_ie(tvb, + offset + 2, info_element_len, + ie_tree); +#ifdef H323 + } +#endif break; default: @@ -2356,6 +2573,29 @@ dissect_q931(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) if (non_locking_shift) codeset = 0; } + + /* + * Heuristic should return TRUE if it get's here. + */ + + return TRUE; + +} + +#ifdef H323 +gboolean +dissect_q931_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + pinfo->current_proto = "Q.931 HEUR"; + return q931_dissector(tvb, pinfo, tree, TRUE); +} +#endif + +void +dissect_q931(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + pinfo->current_proto = "Q.931"; + q931_dissector(tvb, pinfo, tree, FALSE); } void @@ -2387,4 +2627,13 @@ proto_register_q931(void) proto_q931 = proto_register_protocol ("Q.931", "q931"); proto_register_field_array (proto_q931, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); + +} + +void +proto_reg_handoff_q931(void) +{ +#ifdef H323 + heur_dissector_add("tcp", dissect_q931_heur); +#endif } diff --git a/packet-rtcp.c b/packet-rtcp.c index 604f15bac6..d1d9788213 100644 --- a/packet-rtcp.c +++ b/packet-rtcp.c @@ -1,9 +1,10 @@ /* packet-rtcp.c - * Routines for RTCP packet disassembly * - * Jason Lango - * - * $Id: packet-rtcp.c,v 1.5 2000/09/11 16:16:02 gram Exp $ + * Routines for RTCP dissection + * RTCP = Real-time Transport Control Protocol + * + * Copyright 2000, Philips Electronics N.V. + * Written by Andreas Sikkema * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -23,436 +24,1172 @@ * 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_CONFIG_H +# include "config.h" +#endif + +#include +#include "packet.h" #ifdef HAVE_SYS_TYPES_H -#include +# include #endif #ifdef HAVE_NETINET_IN_H -#include +# include #endif +#include #include -#include -#include -#include "packet.h" #include "packet-rtcp.h" -#include "strutil.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; +/* #include "packet-ntp.h" */ +#include "conversation.h" -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) +/* Version is the first 2 bits of the first octet*/ +#define RTCP_VERSION(octet) ((octet) >> 6) + +/* 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[] = +{ + { 0, "Old VAT Version" }, + { 1, "First Draft Version" }, + { 2, "RFC 1889 Version" }, + { 0, NULL }, +}; + +/* 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 }, +}; + +/* 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[] = { - 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, NullTVB, offset, 0, - "Warning: Bad packet length -- " - "data might be incorrect"); + { 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 }, +}; + +/* 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 char rtcp_proto[] = "RTCP"; + +void rtcp_add_address( const unsigned char* ip_addr, int prt ) +{ + address src_addr; + conversation_t* pconv = ( conversation_t* ) NULL; + + src_addr.type = AT_IPv4; + src_addr.len = 4; + src_addr.data = ip_addr; + + /* + * 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 ); + heur_init = TRUE; } - proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, - "Source %d SSRC: %u", sn + 1, rep.rtcp_rr_ssrc); - 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 ); - proto_tree_add_text(rtcp_tree, NullTVB, offset, 1, - "Fraction lost: %u / 256", (unsigned) rep.rtcp_rr_flt); - offset += 1; + /* + * If not, add + */ + if ( ! pconv ) { + conversation_new( &src_addr, &fake_addr, PT_UDP, (guint32) prt, (guint32) 0, (void*) rtcp_proto ); + } - proto_tree_add_text(rtcp_tree, NullTVB, offset, 3, - "Cumulative Packets Lost: %lu", - (((unsigned long) rep.rtcp_rr_cplthi) << 16) + - (unsigned long) rep.rtcp_rr_cplt); - offset += 3; +} - proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, - "Extended Highest Seq #: %lu", - (unsigned long) rep.rtcp_rr_xhiseq); - offset += 4; +#if 0 +static void rtcp_init( void ) +{ + unsigned char* tmp_data; + int i; - proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, - "Jitter: %lu", (unsigned long) rep.rtcp_rr_jitter); - offset += 4; + /* Create a fake adddress... */ + fake_addr.type = AT_IPv4; + fake_addr.len = 4; - proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, - "Last SR timestamp (middle): %lu", - (unsigned long) rep.rtcp_rr_lsr); - offset += 4; + tmp_data = malloc( fake_addr.len ); + for ( i = 0; i < fake_addr.len; i++) { + tmp_data[i] = 0; + } + fake_addr.data = tmp_data; +} +#endif - proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, - "Delay Since Last SR: %lu", - (unsigned long) rep.rtcp_rr_dlsr); - offset += 4; +gboolean +dissect_rtcp_heur( tvbuff_t *tvb, packet_info *pinfo, proto_tree *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. + */ + conversation_t* pconv; + if ( ( pconv = find_conversation( &pi.src, &fake_addr, pi.ptype, pi.srcport, 0 ) ) == NULL ) { + /* + * The source ip:port combination was not what we were looking for, check the destination + */ + if ( ( pconv = find_conversation( &pi.dst, &fake_addr, pi.ptype, pi.destport, 0 ) ) == NULL ) { + return FALSE; + } + } - return offset; + + /* + * An RTCP conversation always contains data + */ + if ( pconv->data == NULL ) + return FALSE; + + /* + * An RTCP conversation data always contains "RTCP" + */ + if ( strcmp( pconv->data, rtcp_proto ) != 0 ) + return FALSE; + + /* + * The message is a valid RTCP message! + */ + dissect_rtcp( tvb, pinfo, tree ); + + return TRUE; } -typedef struct rtcp_rr { - guint32 rtcp_rr_ssrc; -} rtcp_rr_t; 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) +dissect_rtcp_nack( tvbuff_t *tvb, int offset, frame_data *fd, 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, NullTVB, offset, 4, "Sender SSRC: %u", - rr.rtcp_rr_ssrc); + /* 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; + + /* FSN, 16 bits */ + proto_tree_add_uint( tree, hf_rtcp_fsn, tvb, offset, 2, tvb_get_ntohs( tvb, offset ) ); + offset += 2; - for (sn = 0; sn < RTCP_COUNT(hdr); sn++) { - offset = dissect_rtcp_report(hdr, sn, pd, offset, start_packet, - end_packet, rtcp_tree); - } + /* BLP, 16 bits */ + proto_tree_add_uint( tree, hf_rtcp_blp, tvb, offset, 2, tvb_get_ntohs( tvb, offset ) ); + offset += 2; return offset; } -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_fir( tvbuff_t *tvb, int offset, frame_data *fd, 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, NullTVB, 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, NullTVB, offset, 4, "Sender's SSRC: %u", - sr.rtcp_sr_ssrc); - offset += 4; - proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, "NTP timestamp, MSW: %u", - sr.rtcp_sr_ntp_hi); - offset += 4; - proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, "NTP timestamp, LSW: %u", - sr.rtcp_sr_ntp_lo); - offset += 4; - proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, "RTP timestamp: %u", - sr.rtcp_sr_rtp_time); + /* 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; - proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, "Sender's packet count: %u", - sr.rtcp_sr_npackets); + + return offset; +} + +static int +dissect_rtcp_app( tvbuff_t *tvb, int offset, frame_data *fd, proto_tree *tree, + unsigned int padding, unsigned int packet_len ) +{ + 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; - proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, "Sender's octet count: %u", - sr.rtcp_sr_nbytes); + 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; - - for (sn = 0; sn < RTCP_COUNT(hdr); sn++) { - offset = dissect_rtcp_report(hdr, sn, pd, offset, start_packet, - end_packet, rtcp_tree); + 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 ); } + proto_tree_add_item( tree, hf_rtcp_app_data, tvb, offset, packet_len, FALSE ); + offset += packet_len; 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 struct rtcp_chunk_type * -rtcp_find_chunk_type(int type) +static int +dissect_rtcp_bye( tvbuff_t *tvb, int offset, frame_data *fd, proto_tree *tree, + int count ) { - 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 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_uint( tree, hf_rtcp_ssrc_source, tvb, offset, 4, tvb_get_ntohl( tvb, offset ) ); + offset += 4; } - return &unk; + + /* 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++; + + reason_text = ( char* ) 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 ); + free( reason_text ); + offset += reason_length; + + 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_sdes( tvbuff_t *tvb, int offset, frame_data *fd, proto_tree *tree, + int count ) { - unsigned type; - unsigned len; - struct rtcp_chunk_type *ctype; - - if ((offset + 4) > end_packet) - return -1; - proto_tree_add_text(rtcp_tree, NullTVB, offset, 4, "Chunk %d SSRC: %u", - cn + 1, pntohl(&pd[offset])); - offset += 4; - - for (;;) { - if ((offset + 1) > end_packet) - return -1; + 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, 0, + "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, 0, + "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_get_guint8( tvb, offset ) != RTCP_SDES_END ) + && ( tvb_length_remaining( tvb, offset) >= 2 ) ) { + /* while ( ( pd[ offset ] != RTCP_SDES_END ) && ( BYTES_ARE_IN_FRAME( offset, 2 ) ) ) { */ + /* 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++; - type = pd[offset]; - if (type == 0) { - int pad_start = offset; + /* 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++; - /* 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, NullTVB, pad_start, - offset - pad_start, - "(end of chunk and alignment padding)"); - break; + + 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 = ( char * ) 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 ); + free( prefix_string ); + offset += prefix_len; + } + prefix_string = ( char * ) 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 ); + free( prefix_string ); + offset += item_len; } - ctype = rtcp_find_chunk_type(type); + /* Set the length of the items subtree. */ + proto_item_set_len(ti, offset - items_start_offset); - proto_tree_add_text(rtcp_tree, NullTVB, offset, 1, "Chunk type: %s", - ctype->name); - 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 + 1) > end_packet) - return -1; + /* Set the length of this chunk. */ + proto_item_set_len(sdes_item, offset - start_offset); - len = pd[offset]; - proto_tree_add_text(rtcp_tree, NullTVB, offset, 1, "Chunk length: %u", - (unsigned) len); - offset++; + chunk++; + } - if ((offset + len) > end_packet) - return -1; - proto_tree_add_text(rtcp_tree, NullTVB, offset, len, "Chunk string: %s", - format_text(&pd[offset], len)); - offset += len; - } 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, frame_data *fd, proto_tree *tree, + 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, frame_data *fd, proto_tree *tree, + 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, NullTVB, offset, END_OF_FRAME, FALSE); - 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, NullTVB, 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, NullTVB, offset, 1, "Padding: %u", - RTCP_PADDING(&hdr)); - proto_tree_add_text(rtcp_tree, NullTVB, 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, NullTVB, offset, 1, "Type: %u (%s)", - (u_int) hdr.rtcp_type, ptype); - offset++; - - if (offset >= end_offset) - return -1; - proto_tree_add_text(rtcp_tree, NullTVB, offset, 2, "Length / 4 - 1: %u", - (unsigned) hdr.rtcp_length); - offset += 2; + /* 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 ); ?????????????????????????????????????????????????????????????????? + */ + + proto_tree_add_text( tree, tvb, offset, 8, "Timestamp, format unknown" ); + offset += 8; + /* 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; - /* - * Don't add 1 to length, since it's accounted for above. - */ - 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, NullTVB, offset, END_OF_FRAME, - "TYPE NOT HANDLED YET"); - offset = end_packet; - break; - } + /* The rest of the packet is equal to the RR packet */ + if ( count > 0 ) + offset = dissect_rtcp_rr( tvb, offset, fd, tree, count ); - if (offset > 0 && offset < end_packet) { - proto_tree_add_text(rtcp_tree, NullTVB, offset, end_packet - offset, - "Extra data (%d bytes)", end_packet - offset); - } - if (offset < 0) - return offset; - return end_packet; + return offset; } void -dissect_rtcp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) +dissect_rtcp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree ) { - int end_offset; - - OLD_CHECK_DISPLAY_AS_DATA(proto_rtcp, pd, offset, fd, tree); - - if (check_col(fd, COL_PROTOCOL)) - col_add_str(fd, COL_PROTOCOL, "RTCP"); - - if (!tree) - return; - - end_offset = offset + END_OF_FRAME; - while (offset > 0 && offset < end_offset) { - offset = dissect_one_rtcp(pd, offset, fd, tree); + 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; + + pinfo->current_proto = "RTCP"; + + if ( check_col( pinfo->fd, COL_PROTOCOL ) ) { + col_add_str( pinfo->fd, COL_PROTOCOL, "RTCP" ); } - if (offset < 0) { - proto_tree_add_text(tree, NullTVB, end_offset, 0, - "Unexpected end of packet"); + + if ( check_col( pinfo->fd, COL_INFO) ) { + /* The second octet contains the packet type */ + /* switch ( pd[ offset + 1 ] ) { */ + switch ( tvb_get_guint8( tvb, 1 ) ) { + case RTCP_SR: + col_add_str( pinfo->fd, COL_INFO, "Sender Report"); + break; + case RTCP_RR: + col_add_str( pinfo->fd, COL_INFO, "Receiver Report"); + break; + case RTCP_SDES: + col_add_str( pinfo->fd, COL_INFO, "Source Description"); + break; + case RTCP_BYE: + col_add_str( pinfo->fd, COL_INFO, "Goodbye"); + break; + case RTCP_APP: + col_add_str( pinfo->fd, COL_INFO, "Application defined"); + break; + case RTCP_FIR: + col_add_str( pinfo->fd, COL_INFO, "Full Intra-frame Request (H.261)"); + break; + case RTCP_NACK: + col_add_str( pinfo->fd, COL_INFO, "Negative Acknowledgement (H.261)"); + break; + default: + col_add_str( pinfo->fd, COL_INFO, "Unknown packet type"); + break; + } + } + + 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 ( BYTES_ARE_IN_FRAME( offset, 4 ) ) { */ + while ( tvb_length_remaining( 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, pinfo->fd, rtcp_tree, elem_count ); + else offset = dissect_rtcp_rr( tvb, offset, pinfo->fd, 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; + offset = dissect_rtcp_sdes( tvb, offset, pinfo->fd, rtcp_tree, elem_count ); + 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, pinfo->fd, 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; + dissect_rtcp_app( tvb, offset, + pinfo->fd, rtcp_tree, padding_set, + packet_length - 4 ); + break; + case RTCP_FIR: + dissect_rtcp_fir( tvb, offset, pinfo->fd, rtcp_tree ); + break; + case RTCP_NACK: + dissect_rtcp_nack( tvb, offset, pinfo->fd, 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, + "" + } + }, + { + &hf_rtcp_padding, + { + "Padding", + "rtcp.padding", + FT_BOOLEAN, + BASE_NONE, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_rc, + { + "Reception report count", + "rtcp.rc", + FT_UINT8, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_sc, + { + "Source count", + "rtcp.sc", + FT_UINT8, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_pt, + { + "Packet type", + "rtcp.pt", + FT_UINT8, + BASE_DEC, + VALS( rtcp_packet_type_vals ), + 0x0, + "" + } + }, + { + &hf_rtcp_length, + { + "Length", + "rtcp.length", + FT_UINT16, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_ssrc_sender, + { + "Sender SSRC", + "rtcp.senderssrc", + FT_UINT32, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_ntp, + { + "NTP timestamp", + "rtcp.timestamp.ntp", + FT_STRING, + BASE_NONE, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_rtp_timestamp, + { + "RTP timestamp", + "rtcp.timestamp.rtp", + FT_UINT32, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_sender_pkt_cnt, + { + "Sender's packet count", + "rtcp.sender.packetcount", + FT_UINT32, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_sender_oct_cnt, + { + "Sender's octet count", + "rtcp.sender.octetcount", + FT_UINT32, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_ssrc_source, + { + "Identifier", + "rtcp.ssrc.identifier", + FT_UINT32, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_ssrc_fraction, + { + "Fraction lost", + "rtcp.ssrc.fraction", + FT_UINT8, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_ssrc_cum_nr, + { + "Cumulative number of packets lost", + "rtcp.ssrc.cum_nr", + FT_UINT32, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_ssrc_ext_high_seq, + { + "Extended highest sequence number received", + "rtcp.ssrc.ext_high", + FT_UINT32, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_ssrc_high_seq, + { + "Highest sequence number received", + "rtcp.ssrc.high_seq", + FT_UINT16, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_ssrc_high_cycles, + { + "Sequence number cycles count", + "rtcp.ssrc.high_cycles", + FT_UINT16, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_ssrc_jitter, + { + "Interarrival jitter", + "rtcp.ssrc.jitter", + FT_UINT32, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_ssrc_lsr, + { + "Last SR timestamp", + "rtcp.ssrc.lsr", + FT_UINT32, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_ssrc_dlsr, + { + "Delay since last SR timestamp", + "rtcp.ssrc.dlsr", + FT_UINT32, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_ssrc_csrc, + { + "SSRC / CSRC identifier", + "rtcp.sdes.ssrc_csrc", + FT_UINT32, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_ssrc_type, + { + "Type", + "rtcp.sdes.type", + FT_UINT8, + BASE_DEC, + VALS( rtcp_sdes_type_vals ), + 0x0, + "" + } + }, + { + &hf_rtcp_ssrc_length, + { + "Length", + "rtcp.sdes.length", + FT_UINT32, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_ssrc_text, + { + "Text", + "rtcp.sdes.text", + FT_STRING, + BASE_NONE, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_ssrc_prefix_len, + { + "Prefix length", + "rtcp.sdes.prefix.length", + FT_UINT8, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_ssrc_prefix_string, + { + "Prefix string", + "rtcp.sdes.prefix.string", + FT_STRING, + BASE_NONE, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_subtype, + { + "Subtype", + "rtcp.app.subtype", + FT_UINT8, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_name_ascii, + { + "Name (ASCII)", + "rtcp.app.name", + FT_STRING, + BASE_NONE, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_app_data, + { + "Application specific data", + "rtcp.app.data", + FT_BYTES, + BASE_NONE, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_fsn, + { + "First sequence number", + "rtcp.nack.fsn", + FT_UINT16, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_blp, + { + "Bitmask of following lost packets", + "rtcp.nack.blp", + FT_UINT16, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_padding_count, + { + "Padding count", + "rtcp.padding.count", + FT_UINT8, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtcp_padding_data, + { + "Padding data", + "rtcp.padding.data", + FT_BYTES, + BASE_NONE, + NULL, + 0x0, + "" + } + }, +}; + + 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"); + proto_register_field_array(proto_rtcp, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); + +#if 0 + register_init_routine( &rtcp_init ); +#endif } diff --git a/packet-rtcp.h b/packet-rtcp.h index 6e935367d3..a2eba6aaf3 100644 --- a/packet-rtcp.h +++ b/packet-rtcp.h @@ -1,9 +1,10 @@ /* packet-rtcp.h - * Declarations for RTCP packet disassembly * - * Jason Lango - * - * $Id: packet-rtcp.h,v 1.2 2000/08/11 13:34:01 deniel Exp $ + * Routines for RTCP dissection + * RTCP = Real-time Transport Control Protocol + * + * Copyright 2000, Philips Electronics N.V. + * Written by Andreas Sikkema * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -25,9 +26,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef __PACKET_RTCP_H__ -#define __PACKET_RTCP_H__ - -void dissect_rtcp(const u_char *, int, frame_data *, proto_tree *); - -#endif +void rtcp_add_address ( const unsigned char* ip_addr, int prt ); +gboolean dissect_rtcp_heur ( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree ); +void dissect_rtcp ( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree ); +void proto_register_rtcp( void ); diff --git a/packet-rtp.c b/packet-rtp.c index 88ee2a15bc..6f6008b6ac 100644 --- a/packet-rtp.c +++ b/packet-rtp.c @@ -1,9 +1,10 @@ /* packet-rtp.c - * Routines for RTP packet disassembly * - * Jason Lango - * - * $Id: packet-rtp.c,v 1.5 2000/08/13 14:08:43 deniel Exp $ + * Routines for RTP dissection + * RTP = Real time Transport Protocol + * + * Copyright 2000, Philips Electronics N.V. + * Written by Andreas Sikkema * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -23,195 +24,596 @@ * 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 RTP protocol according to Annex A + * of ITU-T Recommendation H.225.0 (02/98) or RFC 1889 * - * + * RTP traffic is handled by an even UDP portnumber. This can be any + * port number, but there is a registered port available, port 5004 + * See Annex B of ITU-T Recommendation H.225.0, section B.7 */ -#include "config.h" + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include "packet.h" #ifdef HAVE_SYS_TYPES_H -#include +# include #endif #ifdef HAVE_NETINET_IN_H -#include +# include #endif +#include #include -#include -#include -#include -#include "packet.h" #include "packet-rtp.h" +#include "packet-h261.h" +#include "conversation.h" + +/* RTP header fields */ +static int proto_rtp = -1; +static int hf_rtp_version = -1; +static int hf_rtp_padding = -1; +static int hf_rtp_extension = -1; +static int hf_rtp_csrc_count = -1; +static int hf_rtp_marker = -1; +static int hf_rtp_payload_type = -1; +static int hf_rtp_seq_nr = -1; +static int hf_rtp_timestamp = -1; +static int hf_rtp_ssrc = -1; +static int hf_rtp_csrc_item = -1; +static int hf_rtp_data = -1; +static int hf_rtp_padding_data = -1; +static int hf_rtp_padding_count= -1; + +/* RTP header extension fields */ +static int hf_rtp_prof_define = -1; +static int hf_rtp_length = -1; +static int hf_rtp_hdr_ext = -1; + +/* RTP fields defining a sub tree */ +static gint ett_rtp = -1; +static gint ett_csrc_list = -1; +static gint ett_hdr_ext = -1; + +/* + * Fields in the first octet of the RTP header. + */ -static int proto_rtp = -1; +/* Version is the first 2 bits of the first octet*/ +#define RTP_VERSION(octet) ((octet) >> 6) -static gint ett_rtp = -1; +/* Padding is the third bit; No need to shift, because true is any value + other than 0! */ +#define RTP_PADDING(octet) ((octet) & 0x20) -#define _RTP_FLAG_BITS(hdr, s, n) \ - ((u_int)(((hdr)->rtp_flag_bits >> (8 - (s) - (n))) & ((1 << (n)) - 1))) -#define RTP_VERSION(hdr) _RTP_FLAG_BITS(hdr, 0, 2) -#define RTP_PADDING(hdr) _RTP_FLAG_BITS(hdr, 2, 1) -#define RTP_EXTENSION(hdr) _RTP_FLAG_BITS(hdr, 3, 1) -#define RTP_CSRC_COUNT(hdr) _RTP_FLAG_BITS(hdr, 4, 4) +/* Extension bit is the fourth bit */ +#define RTP_EXTENSION(octet) ((octet) & 0x10) -#define RTP_MARKER(hdr) ((u_int)((hdr)->rtp_type_bits >> 7)) -#define RTP_PAYLOAD_TYPE(hdr) ((u_int)((hdr)->rtp_type_bits & 0x7F)) +/* CSRC count is the last four bits */ +#define RTP_CSRC_COUNT(octet) ((octet) & 0xF) -typedef struct rtp_hdr { - guint8 rtp_flag_bits; - guint8 rtp_type_bits; - guint16 rtp_seq; - guint32 rtp_timestamp; - guint32 rtp_ssrc; -} rtp_hdr_t; +static const value_string rtp_version_vals[] = +{ + { 0, "Old VAT Version" }, + { 1, "First Draft Version" }, + { 2, "RFC 1889 Version" }, + { 0, NULL }, +}; + +/* + * Fields in the second octet of the RTP header. + */ -typedef struct rtp_hdr_ext { - guint16 rtp_ext_app; /* defined by RTP profile */ - guint16 rtp_ext_length; /* length of extension data in 32 bit words */ -} rtp_hdr_ext_t; +/* Marker is the first bit of the second octet */ +#define RTP_MARKER(octet) ((octet) & 0x80) -void -dissect_rtp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) +/* Payload type is the last 7 bits */ +#define RTP_PAYLOAD_TYPE(octet) ((octet) & 0x7F) + +/* + * RTP Payload types + * Table B.2 / H.225.0 + */ +#define PT_PCMU 0 +#define PT_PCMA 8 +#define PT_G722 9 +#define PT_G723 4 +#define PT_G728 15 +#define PT_G729 18 +#define PT_H261 31 +#define PT_H263 34 + +static const value_string rtp_payload_type_vals[] = +{ + { PT_PCMU, "ITU-T G.711 PCMU" }, + { PT_PCMA, "ITU-T G.711 PCMA" }, + { PT_G722, "ITU-T G.722" }, + { PT_G723, "ITU-T G.723" }, + { PT_G728, "ITU-T G.728" }, + { PT_G729, "ITU-T G.729" }, + { PT_H261, "ITU-T H.261" }, + { PT_H263, "ITU-T H.263" }, + { 0, NULL }, +}; + +static address fake_addr; +static int heur_init = FALSE; + +static const char rtp_proto[] = "RTP"; + +void rtp_add_address( const unsigned char* ip_addr, int prt ) { - proto_tree *rtp_tree; - proto_item *ti; - const u_char *data, *dataend; - rtp_hdr_t hdr; - int end_offset; - int ii; - guint32 *csrc_ptr; - rtp_hdr_ext_t ext; - - OLD_CHECK_DISPLAY_AS_DATA(proto_rtp, pd, offset, fd, tree); - - data = &pd[offset]; - dataend = data + END_OF_FRAME; - end_offset = offset + END_OF_FRAME; - - memcpy(&hdr, data, END_OF_FRAME < sizeof(rtp_hdr_t) ? - END_OF_FRAME : sizeof(rtp_hdr_t)); - hdr.rtp_seq = ntohs(hdr.rtp_seq); - hdr.rtp_timestamp = ntohl(hdr.rtp_timestamp); - hdr.rtp_ssrc = ntohl(hdr.rtp_ssrc); - - if (check_col(fd, COL_PROTOCOL)) - col_add_str(fd, COL_PROTOCOL, "RTP"); - if (check_col(fd, COL_INFO)) { - col_add_fstr(fd, COL_INFO, "SSRC=%lu, Seq=%u, Time=%lu%s", - (u_long) hdr.rtp_ssrc, - (u_int) hdr.rtp_seq, - (u_long) hdr.rtp_timestamp, - RTP_MARKER(&hdr) ? ", Mark" : ""); + address src_addr; + conversation_t* pconv = ( conversation_t* ) NULL; + + src_addr.type = AT_IPv4; + src_addr.len = 4; + src_addr.data = ip_addr; + + /* + * The first time the function is called let the tcp dissector + * know that we're interested in traffic + */ + if ( ! heur_init ) { + heur_dissector_add( "udp", dissect_rtp_heur ); + heur_init = TRUE; } - rtp_tree = NULL; + /* + * Check if the ip address an dport combination is not + * already registered + */ + pconv = find_conversation( &src_addr, &fake_addr, PT_UDP, prt, 0 ); + + /* + * If not, add + */ + if ( ! pconv ) { + conversation_new( &src_addr, &fake_addr, PT_UDP, (guint32) prt, (guint32) 0, ( void * ) rtp_proto ); + } + +} + +#if 0 +static void rtp_init( void ) +{ + unsigned char* tmp_data; + int i; + + /* Create a fake adddress... */ + fake_addr.type = AT_IPv4; + fake_addr.len = 4; - if (tree) { - ti = proto_tree_add_item(tree, proto_rtp, NullTVB, offset, END_OF_FRAME, - FALSE); - rtp_tree = proto_item_add_subtree(ti, ett_rtp); + tmp_data = malloc( fake_addr.len ); + for ( i = 0; i < fake_addr.len; i++) { + tmp_data[i] = 0; } + fake_addr.data = tmp_data; +} +#endif - if (!rtp_tree) - return; - - if (offset >= end_offset) - goto bad_len; - proto_tree_add_text(rtp_tree, NullTVB, offset, 1, "Version: %u (%s)", - RTP_VERSION(&hdr), - RTP_VERSION(&hdr) == 3 ? "New Unknown Version" : - RTP_VERSION(&hdr) == 2 ? "RFC 1889 Version" : - RTP_VERSION(&hdr) == 1 ? "First Draft Version" : - "Old Vat Version"); - proto_tree_add_text(rtp_tree, NullTVB, offset, 1, "Padding: %u", - RTP_PADDING(&hdr)); - proto_tree_add_text(rtp_tree, NullTVB, offset, 1, "Extension: %u", - RTP_EXTENSION(&hdr)); - proto_tree_add_text(rtp_tree, NullTVB, offset, 1, "CSRC Count: %u", - RTP_CSRC_COUNT(&hdr)); - offset++; - - if (offset >= end_offset) - goto bad_len; - proto_tree_add_text(rtp_tree, NullTVB, offset, 1, "Marker: %u", - RTP_MARKER(&hdr)); - proto_tree_add_text(rtp_tree, NullTVB, offset, 1, "Payload Type: %u", - RTP_PAYLOAD_TYPE(&hdr)); - offset++; - - if (offset >= end_offset) - goto bad_len; - proto_tree_add_text(rtp_tree, NullTVB, offset, 2, "Seq: %u", - (u_int) hdr.rtp_seq); - offset += 2; - - if (offset >= end_offset) - goto bad_len; - proto_tree_add_text(rtp_tree, NullTVB, offset, 4, "Timestamp: %lu", - (u_long) hdr.rtp_timestamp); - offset += 4; - - if (offset >= end_offset) - goto bad_len; - proto_tree_add_text(rtp_tree, NullTVB, offset, 4, "SSRC: %lu", - (u_long) hdr.rtp_ssrc); - offset += 4; - - csrc_ptr = (guint32*) (data + sizeof(rtp_hdr_t)); - for (ii = 0; ii < RTP_CSRC_COUNT(&hdr); ii++) { - guint32 csrc; - if (offset >= end_offset) - goto bad_len; - csrc = pntohl(csrc_ptr); - proto_tree_add_text(rtp_tree, NullTVB, offset, 4, "CSRC %d: %lu", - ii + 1, (u_long) csrc); - offset += 4; - csrc_ptr++; +gboolean +dissect_rtp_heur( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree ) +{ + /* This is a heuristic dissector, which means we get all the tcp traffic + * not send to a known dissector! + * So we first check if the frame is really meant for us. + */ + conversation_t* pconv; + if ( ( pconv = find_conversation( &pi.src, &fake_addr, pi.ptype, pi.srcport, 0 ) ) == NULL ) { + /* + * The source ip:port combination was not what we were looking for, check the destination + */ + if ( ( pconv = find_conversation( &pi.dst, &fake_addr, pi.ptype, pi.destport, 0 ) ) == NULL ) { + return FALSE; + } } - if (RTP_EXTENSION(&hdr)) { - memcpy(&ext, data + sizeof(rtp_hdr_t), - END_OF_FRAME < sizeof(rtp_hdr_ext_t) ? - END_OF_FRAME : sizeof(rtp_hdr_ext_t)); - ext.rtp_ext_app = ntohs(ext.rtp_ext_app); - ext.rtp_ext_length = ntohs(ext.rtp_ext_length); + /* + * An RTP conversation always contains data + */ + if ( pconv->data == NULL ) + return FALSE; - proto_tree_add_text(rtp_tree, NullTVB, offset, 2, - "Extension-defined: %x", (u_int) ext.rtp_ext_app); - offset += 2; - proto_tree_add_text(rtp_tree, NullTVB, offset, 2, - "Extension length: %u", (u_int) ext.rtp_ext_length); - offset += 2; - proto_tree_add_text(rtp_tree, NullTVB, offset, 4 * ext.rtp_ext_length, - "Extension Data (%d bytes)", - (int) 4 * ext.rtp_ext_length); - offset += 4 * ext.rtp_ext_length; + /* + * An RTP conversation data always contains "RTP" + */ + if ( strcmp( pconv->data, rtp_proto ) != 0 ) + return FALSE; + + dissect_rtp( tvb, pinfo, tree ); + + return TRUE; +} + +void +dissect_rtp_data( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_tree *rtp_tree, int offset, unsigned int data_len, unsigned int payload_type ) +{ + tvbuff_t *newtvb; + + switch( payload_type ) { + case PT_H261: + /* + * What does reported length DO? + */ + newtvb = tvb_new_subset( tvb, offset, data_len, -1 ); + dissect_h261(newtvb, pinfo, tree); + break; + default: + proto_tree_add_bytes( rtp_tree, hf_rtp_data, tvb, offset, data_len, tvb_get_ptr( tvb, offset, data_len ) ); + break; } +} - proto_tree_add_text(rtp_tree, NullTVB, offset, END_OF_FRAME, - "Data (%d bytes)", END_OF_FRAME); +void +dissect_rtp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree ) +{ + proto_item *ti = NULL; + proto_tree *rtp_tree = NULL; + proto_tree *rtp_csrc_tree = NULL; + guint8 octet; + unsigned int version; + gboolean padding_set; + gboolean extension_set; + unsigned int csrc_count; + gboolean marker_set; + unsigned int payload_type; + unsigned int i = 0; + unsigned int hdr_extension= 0; + unsigned int padding_count= 0; + unsigned int offset = 0; + guint16 seq_num; + guint32 timestamp; + guint32 sync_src; + guint32 csrc_item; + + pinfo->current_proto = "RTP"; + + /* Get the fields in the first octet */ + octet = tvb_get_guint8( tvb, offset ); + version = RTP_VERSION( octet ); + padding_set = RTP_PADDING( octet ); + extension_set = RTP_EXTENSION( octet ); + csrc_count = RTP_CSRC_COUNT( octet ); + + /* Get the fields in the second octet */ + octet = tvb_get_guint8( tvb, offset + 1 ); + marker_set = RTP_MARKER( octet ); + payload_type = RTP_PAYLOAD_TYPE( octet ); + + /* Get the subsequent fields */ + seq_num = tvb_get_ntohs( tvb, offset + 2 ); + timestamp = tvb_get_ntohl( tvb, offset + 4 ); + sync_src = tvb_get_ntohl( tvb, offset + 8 ); + + if ( check_col( pinfo->fd, COL_PROTOCOL ) ) { + col_add_str( pinfo->fd, COL_PROTOCOL, "RTP" ); + } + + if ( check_col( pinfo->fd, COL_INFO) ) { + col_add_fstr( pinfo->fd, COL_INFO, + "Payload type=%s, SSRC=%u, Seq=%u, Time=%u%s", + val_to_str( payload_type, rtp_payload_type_vals, + "Unknown (%u)" ), + sync_src, + seq_num, + timestamp, + marker_set ? ", Mark" : ""); + } + + if ( tree ) { + ti = proto_tree_add_item( tree, proto_rtp, tvb, offset, tvb_length_remaining( tvb, offset ), FALSE ); + rtp_tree = proto_item_add_subtree( ti, ett_rtp ); + + proto_tree_add_uint( rtp_tree, hf_rtp_version, tvb, + offset, 1, version ); + proto_tree_add_boolean( rtp_tree, hf_rtp_padding, tvb, + offset, 1, padding_set ); + proto_tree_add_boolean( rtp_tree, hf_rtp_extension, tvb, + offset, 1, extension_set ); + proto_tree_add_uint( rtp_tree, hf_rtp_csrc_count, tvb, + offset, 1, csrc_count ); + offset++; + + proto_tree_add_boolean( rtp_tree, hf_rtp_marker, tvb, offset, + 1, marker_set ); + proto_tree_add_uint( rtp_tree, hf_rtp_payload_type, tvb, + offset, 1, payload_type ); + offset++; + + /* Sequence number 16 bits (2 octets) */ + proto_tree_add_uint( rtp_tree, hf_rtp_seq_nr, tvb, offset, 2, seq_num ); + offset += 2; + + /* Timestamp 32 bits (4 octets) */ + proto_tree_add_uint( rtp_tree, hf_rtp_timestamp, tvb, offset, 4, timestamp ); + offset += 4; - return; + /* Synchronization source identifier 32 bits (4 octets) */ + proto_tree_add_uint( rtp_tree, hf_rtp_ssrc, tvb, offset, 4, sync_src ); + offset += 4; -bad_len: - proto_tree_add_text(rtp_tree, NullTVB, end_offset, 0, - "Unexpected end of packet"); + /* CSRC list*/ + if ( csrc_count > 0 ) { + ti = proto_tree_add_text(rtp_tree, tvb, offset, csrc_count * 4, "Contributing Source identifiers"); + rtp_csrc_tree = proto_item_add_subtree( ti, ett_csrc_list ); + for (i = 0; i < csrc_count; i++ ) { + csrc_item = tvb_get_ntohl( tvb, offset ); + proto_tree_add_uint_format( rtp_csrc_tree, + hf_rtp_csrc_item, tvb, offset, 4, + csrc_item, + "CSRC item %d: %u", + i, csrc_item ); + offset += 4; + } + } + + /* Optional RTP header extension */ + if ( extension_set ) { + /* Defined by profile field is 16 bits (2 octets) */ + proto_tree_add_uint( rtp_tree, hf_rtp_prof_define, tvb, offset, 2, tvb_get_ntohs( tvb, offset ) ); + offset += 2; + + hdr_extension = tvb_get_ntohs( tvb, offset ); + proto_tree_add_uint( rtp_tree, hf_rtp_length, tvb, + offset, 2, hdr_extension); + if ( hdr_extension > 0 ) { + ti = proto_tree_add_text(rtp_tree, tvb, offset, csrc_count * 4, "Header extensions"); + /* I'm re-using the old tree variable here + from the CSRC list!*/ + rtp_csrc_tree = proto_item_add_subtree( ti, + ett_hdr_ext ); + for (i = 0; i < hdr_extension; i++ ) { + proto_tree_add_uint( rtp_csrc_tree, hf_rtp_hdr_ext, tvb, offset, 4, tvb_get_ntohl( tvb, offset ) ); + offset += 4; + } + } + } + /* Find the padding + * The padding count is found in the LAST octet of the packet + * This contains the number of octets that can be ignored at + * the end of the packet + */ + if ( padding_set ) { + padding_count = tvb_get_guint8( tvb, tvb_length( tvb ) - 1 ); + if ( padding_count > 0 ) { + dissect_rtp_data( tvb, pinfo, tree, rtp_tree, offset, tvb_length( tvb ) - padding_count, payload_type ); + offset = tvb_length( tvb ) - padding_count; + proto_tree_add_item( rtp_tree, hf_rtp_padding_data, tvb, offset, padding_count - 1, FALSE ); + offset += padding_count - 1; + proto_tree_add_item( rtp_tree, hf_rtp_padding_count, tvb, offset, 1, FALSE ); + } + else { + proto_tree_add_item( rtp_tree, hf_rtp_padding_count, tvb, tvb_length( tvb ) - 1, 1, FALSE ); + } + } + else { + dissect_rtp_data( tvb, pinfo, tree, rtp_tree, offset, tvb_length_remaining( tvb, offset ) - padding_count, payload_type ); + } + } } void proto_register_rtp(void) { -/* static hf_register_info hf[] = { - { &variable, - { "Name", "rtp.abbreviation", TYPE, VALS_POINTER }}, - };*/ - static gint *ett[] = { + static hf_register_info hf[] = + { + { + &hf_rtp_version, + { + "Version", + "rtp.version", + FT_UINT8, + BASE_DEC, + VALS(rtp_version_vals), + 0x0, + "" + } + }, + { + &hf_rtp_padding, + { + "Padding", + "rtp.padding", + FT_BOOLEAN, + BASE_NONE, + NULL, + 0x0, + "" + } + }, + { + &hf_rtp_extension, + { + "Extension", + "rtp.ext", + FT_BOOLEAN, + BASE_NONE, + NULL, + 0x0, + "" + } + }, + { + &hf_rtp_csrc_count, + { + "Contributing source identifiers count", + "rtp.cc", + FT_UINT8, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtp_marker, + { + "Marker", + "rtp.marker", + FT_BOOLEAN, + BASE_NONE, + NULL, + 0x0, + "" + } + }, + { + &hf_rtp_payload_type, + { + "Payload type", + "rtp.p_type", + FT_UINT8, + BASE_DEC, + VALS(rtp_payload_type_vals), + 0x0, + "" + } + }, + { + &hf_rtp_seq_nr, + { + "Sequence number", + "rtp.seq", + FT_UINT16, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtp_timestamp, + { + "Timestamp", + "rtp.timestamp", + FT_UINT32, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtp_ssrc, + { + "Synchronization Source identifier", + "rtp.ssrc", + FT_UINT32, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtp_prof_define, + { + "Defined by profile", + "rtp.ext.profile", + FT_UINT16, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtp_length, + { + "Extension length", + "rtp.ext.len", + FT_UINT16, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtp_csrc_item, + { + "CSRC item", + "rtp.csrc.item", + FT_UINT32, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtp_hdr_ext, + { + "Header extension", + "rtp.hdr_ext", + FT_UINT32, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_rtp_data, + { + "Payload", + "rtp.payload", + FT_BYTES, + BASE_HEX, + NULL, + 0x0, + "" + } + }, + { + &hf_rtp_padding_data, + { + "Padding data", + "rtp.padding.data", + FT_BYTES, + BASE_HEX, + NULL, + 0x0, + "" + } + }, + { + &hf_rtp_padding_count, + { + "Padding count", + "rtp.padding.count", + FT_UINT8, + BASE_DEC, + NULL, + 0x0, + "" + } + }, +}; + + static gint *ett[] = + { &ett_rtp, + &ett_csrc_list, + &ett_hdr_ext, }; - proto_rtp = proto_register_protocol("Realtime Transport Protocol", "rtp"); - /* proto_register_field_array(proto_rtp, hf, array_length(hf));*/ + + proto_rtp = proto_register_protocol("Real-Time Transport Protocol", "rtp"); + proto_register_field_array(proto_rtp, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); + +#if 0 + register_init_routine( &rtp_init ); +#endif } diff --git a/packet-rtp.h b/packet-rtp.h index 8d8ab631bf..8df5092c45 100644 --- a/packet-rtp.h +++ b/packet-rtp.h @@ -1,9 +1,10 @@ /* packet-rtp.h - * Declarations for RTP packet disassembly * - * Jason Lango - * - * $Id: packet-rtp.h,v 1.2 2000/08/11 13:34:01 deniel Exp $ + * Routines for RTP dissection + * RTP = Real time Transport Protocol + * + * Copyright 2000, Philips Electronics N.V. + * Written by Andreas Sikkema * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -25,9 +26,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef __PACKET_RTP_H__ -#define __PACKET_RTP_H__ - -void dissect_rtp(const u_char *, int, frame_data *, proto_tree *); - -#endif +void rtp_add_address ( const unsigned char* ip_addr, int prt ); +gboolean dissect_rtp_heur ( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree ); +void dissect_rtp ( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree ); +void proto_register_rtp( void ); diff --git a/packet-rtsp.c b/packet-rtsp.c index 257c4c3207..da9e88087a 100644 --- a/packet-rtsp.c +++ b/packet-rtsp.c @@ -4,7 +4,7 @@ * Jason Lango * Liberally copied from packet-http.c, by Guy Harris * - * $Id: packet-rtsp.c,v 1.19 2000/09/30 05:46:27 guy Exp $ + * $Id: packet-rtsp.c,v 1.20 2000/10/19 06:45:11 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -126,14 +126,14 @@ rtsp_create_conversation(const u_char *trans_begin, const u_char *trans_end) conv = conversation_new(&pi.src, &pi.dst, PT_UDP, s_data_port, c_data_port, 0); - old_conversation_set_dissector(conv, dissect_rtp); + conversation_set_dissector(conv, dissect_rtp); if (!c_mon_port || !s_mon_port) return; conv = conversation_new(&pi.src, &pi.dst, PT_UDP, s_mon_port, c_mon_port, 0); - old_conversation_set_dissector(conv, dissect_rtcp); + conversation_set_dissector(conv, dissect_rtcp); } static void dissect_rtsp(const u_char *pd, int offset, frame_data *fd, diff --git a/packet-tpkt.c b/packet-tpkt.c new file mode 100644 index 0000000000..fb71911573 --- /dev/null +++ b/packet-tpkt.c @@ -0,0 +1,187 @@ +/* packet-tpkt.c + * + * Routines for TPKT dissection + * Copyright 2000, Philips Electronics N.V. + * Andreas Sikkema + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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 TPKT protocol according to + * RFC 1006 + * + * IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT + * + * Please examine the dissector. It is NOT defined in the normal way! + * Some variables are references and the dissector also returns a + * value! And no, this is not a heuristic dissector! + * + * IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT + */ + + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include "packet.h" + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#include +#include + +#include "packet-tpkt.h" + +/* TPKT header fields */ +static int proto_tpkt = -1; +static int hf_tpkt_version = -1; +static int hf_tpkt_reserved = -1; +static int hf_tpkt_length = -1; + +/* TPKT fields defining a sub tree */ +static gint ett_tpkt = -1; + +int +is_tpkt( tvbuff_t *tvb, unsigned int* offset ) +{ + if ( (*offset) + 4 > tvb_length( tvb ) ) return FALSE; + if ( ! ( ( tvb_get_guint8( tvb, ( *offset ) ) == 3 ) && + ( tvb_get_guint8( tvb, ( *offset ) + 1 ) == 0 ) ) ) return FALSE; + + return TRUE; +} + +int +dissect_tpkt( tvbuff_t *tvb, unsigned int* offset, packet_info *pinfo, proto_tree *tree ) +{ + proto_item *ti = NULL; + proto_tree *tpkt_tree = NULL; + unsigned int data_len = 0; + + + pinfo->current_proto = "TPKT"; + + /* There should at least be 4 bytes left in the frame */ + if ( (*offset) + 4 > tvb_length( tvb ) ) return -1; + /* + * The first octet should be 3 and the second one should be 0 + * The H.323 implementers guide suggests that this migh not + * always be the case.... + */ + if ( ! ( ( tvb_get_guint8( tvb, ( *offset ) ) == 3 ) && + ( tvb_get_guint8( tvb, ( *offset ) + 1 ) == 0 ) ) ) return -1; + + if ( check_col( pinfo->fd, COL_PROTOCOL ) ) { + col_add_str( pinfo->fd, COL_PROTOCOL, "TPKT" ); + } + + if ( check_col( pinfo->fd, COL_INFO) ) { + /*data_len = pntohs( &pd[ (*offset) + 2 ] );*/ + data_len = tvb_get_ntohs( tvb, (*offset) + 2 ); + + col_add_fstr( pinfo->fd, COL_INFO, "TPKT Data length = %d", data_len ); + } + + if ( tree ) { + ti = proto_tree_add_item( tree, proto_tpkt, tvb, (*offset), 4, FALSE ); + tpkt_tree = proto_item_add_subtree( ti, ett_tpkt ); + /* Version 1st octet */ + proto_tree_add_item( tpkt_tree, hf_tpkt_version, tvb, (*offset), 1, FALSE ); + (*offset)++; + /* Reserved octet*/ + proto_tree_add_item( tpkt_tree, hf_tpkt_reserved, tvb, (*offset), 1, FALSE ); + (*offset)++; + } + else { + (*offset) += 2; + } + /* Length, two octets */ + /*data_len = pntohs( &pd[ (*offset) ] );*/ + data_len = tvb_get_ntohs( tvb, (*offset) ); + + if ( tree ) + proto_tree_add_uint_format( tpkt_tree, hf_tpkt_length, tvb, (*offset), 2, data_len, "Length: %d", data_len ); + + (*offset) += 2; + return data_len; +} + +void +proto_register_tpkt(void) +{ + static hf_register_info hf[] = + { + { + &hf_tpkt_version, + { + "Version", + "tpkt.version", + FT_UINT8, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_tpkt_reserved, + { + "Reserved", + "tpkt.reserved", + FT_UINT8, + BASE_DEC, + NULL, + 0x0, + "" + } + }, + { + &hf_tpkt_length, + { + "Length", + "tpkt.length", + FT_UINT16, + BASE_DEC, + NULL, + 0x0, + "" + } + }, +}; + + static gint *ett[] = + { + &ett_tpkt, + }; + + + proto_tpkt = proto_register_protocol("TPKT", "tpkt"); + proto_register_field_array(proto_tpkt, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); +} diff --git a/packet-tpkt.h b/packet-tpkt.h new file mode 100644 index 0000000000..2697a20196 --- /dev/null +++ b/packet-tpkt.h @@ -0,0 +1,30 @@ +/* packet-tpkt.h + * + * Routines for TPKT dissection + * + * Copyright 2000, Philips Electronics N.V. + * Andreas Sikkema + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +int is_tpkt( tvbuff_t *tvb, unsigned int* offset ); +int dissect_tpkt( tvbuff_t *tvb, unsigned int* offset, packet_info *pinfo, proto_tree *tree ); +void proto_register_tpkt( void ); -- cgit v1.2.3