diff options
author | Luis Ontanon <luis.ontanon@gmail.com> | 2005-02-19 22:43:38 +0000 |
---|---|---|
committer | Luis Ontanon <luis.ontanon@gmail.com> | 2005-02-19 22:43:38 +0000 |
commit | f18141e49bf3db88d87fc63d9d1a80fbbfa1f45b (patch) | |
tree | 2bc6874521bd1895052a9c430ad3cf3cab5df3c6 /epan/dissectors | |
parent | 59ef46c037b7fb59c59c7a613935732c6de70b75 (diff) |
From Martin Mathielson
RDT (Realplayer Data Protocol) dissector and patch RTSP to create RDT conversations
svn path=/trunk/; revision=13431
Diffstat (limited to 'epan/dissectors')
-rw-r--r-- | epan/dissectors/Makefile.common | 1 | ||||
-rw-r--r-- | epan/dissectors/packet-rdt.c | 494 | ||||
-rw-r--r-- | epan/dissectors/packet-rdt.h | 42 | ||||
-rw-r--r-- | epan/dissectors/packet-rtsp.c | 63 |
4 files changed, 583 insertions, 17 deletions
diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common index 5c777b804b..91dd29d386 100644 --- a/epan/dissectors/Makefile.common +++ b/epan/dissectors/Makefile.common @@ -451,6 +451,7 @@ DISSECTOR_SRC = \ packet-radiotap.c \ packet-ranap.c \ packet-raw.c \ + packet-rdt.c \ packet-redback.c \ packet-retix-bpdu.c \ packet-rip.c \ diff --git a/epan/dissectors/packet-rdt.c b/epan/dissectors/packet-rdt.c new file mode 100644 index 0000000000..7e0af1a133 --- /dev/null +++ b/epan/dissectors/packet-rdt.c @@ -0,0 +1,494 @@ +/* packet-rdt.c + * + * Routines for RDT dissection + * RDT = Real Data Transport + * + * Copyright 2005 + * Written by Martin Mathieson + * + * $Id: packet-rdt.c 13357 2005-02-08 21:12:54Z lroland $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@ethereal.com> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <glib.h> +#include <epan/packet.h> + +#include <stdio.h> +#include <string.h> + +#include "packet-rdt.h" +#include <epan/conversation.h> + +#include <epan/prefs.h> + +static dissector_handle_t rdt_handle; + +/* RDT header fields */ +static int proto_rdt = -1; + +/* RDT setup fields */ +static int hf_rdt_setup = -1; +static int hf_rdt_setup_frame = -1; +static int hf_rdt_setup_method = -1; +static int hf_rdt_stream_id = -1; +static int hf_rdt_sequence_number = -1; +static int hf_rdt_flags = -1; +static int hf_rdt_packet_size = -1; +static int hf_rdt_timestamp = -1; +static int hf_rdt_unparsed = -1; + +/* RDT fields defining a sub tree */ +static gint ett_rdt = -1; +static gint ett_rdt_setup = -1; + +static void dissect_rdt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); +static void show_setup_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); + +/* Preferences bool to control whether or not setup info should be shown */ +static gboolean global_rdt_show_setup_info = TRUE; + +/* Memory chunk for storing conversation and per-packet info */ +static GMemChunk *rdt_conversations = NULL; + + +#define RETRANSMISSION_REQUEST_STREAM_ID 0 +#define AUDIO_STREAM_ID 64 +#define VIDEO_STREAM_ID 66 + +const value_string rdt_stream_id_vals[] = +{ + { RETRANSMISSION_REQUEST_STREAM_ID, "Retransmission Request" }, + { AUDIO_STREAM_ID, "Audio" }, + { VIDEO_STREAM_ID, "Video" }, + { 0, NULL }, +}; + + +/* Set up an RDT conversation */ +void rdt_add_address(packet_info *pinfo, + address *addr, int port, + int other_port, + gchar *setup_method, guint32 setup_frame_number) +{ + address null_addr; + conversation_t* p_conv; + struct _rdt_conversation_info *p_conv_data = NULL; + + /* + * If this isn't the first time this packet has been processed, + * we've already done this work, so we don't need to do it + * again. + */ + if (pinfo->fd->flags.visited) + { + return; + } + + SET_ADDRESS(&null_addr, AT_NONE, 0, NULL); + + /* + * Check if the ip address and port combination is not + * already registered as a conversation. + */ + p_conv = find_conversation(setup_frame_number, addr, &null_addr, PT_UDP, port, other_port, + NO_ADDR_B | (!other_port ? NO_PORT_B : 0)); + + /* + * If not, create a new conversation. + */ + if ( !p_conv || p_conv->setup_frame != setup_frame_number) + { + p_conv = conversation_new(setup_frame_number, addr, &null_addr, PT_UDP, + (guint32)port, (guint32)other_port, + NO_ADDR2 | (!other_port ? NO_PORT2 : 0)); + } + + /* Set dissector */ + conversation_set_dissector(p_conv, rdt_handle); + + /* + * Check if the conversation has data associated with it. + */ + p_conv_data = conversation_get_proto_data(p_conv, proto_rdt); + + /* + * If not, add a new data item. + */ + if (!p_conv_data) + { + /* Create conversation data */ + p_conv_data = g_mem_chunk_alloc(rdt_conversations); + + conversation_add_proto_data(p_conv, proto_rdt, p_conv_data); + } + + /* + * Update the conversation data. + */ + strncpy(p_conv_data->method, setup_method, MAX_RDT_SETUP_METHOD_SIZE); + p_conv_data->method[MAX_RDT_SETUP_METHOD_SIZE] = '\0'; + p_conv_data->frame_number = setup_frame_number; +} + +static void rdt_init(void) +{ + /* (Re)allocate mem chunk for conversations */ + if (rdt_conversations) + { + g_mem_chunk_destroy(rdt_conversations); + } + + rdt_conversations = g_mem_chunk_new("rdt_conversations", + sizeof(struct _rdt_conversation_info), + 20 * sizeof(struct _rdt_conversation_info), + G_ALLOC_ONLY); +} + + + +/*********************************/ +/* Main dissection function */ +/*********************************/ +static void +dissect_rdt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + guint offset = 0; + proto_item *ti = NULL; + proto_tree *rdt_tree = NULL; + guint8 stream_id; + guint16 sequence_number; + guint16 packet_size; + guint32 timestamp; + guint8 flags; + + /* Set columns */ + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + { + col_set_str(pinfo->cinfo, COL_PROTOCOL, "RDT" ); + } + if (check_col(pinfo->cinfo, COL_INFO)) + { + col_set_str(pinfo->cinfo, COL_INFO, "RealPlayer: "); + } + + /* Build tree (inside guard?) */ + /* Create RDT protocol tree */ + ti = proto_tree_add_item(tree, proto_rdt, tvb, offset, -1, FALSE); + rdt_tree = proto_item_add_subtree(ti, ett_rdt); + + /* Conversation setup info */ + if (global_rdt_show_setup_info) + { + show_setup_info(tvb, pinfo, rdt_tree); + } + + + /* Stream ID */ + stream_id = tvb_get_guint8(tvb, offset); + proto_tree_add_item(rdt_tree, hf_rdt_stream_id, tvb, offset, 1, FALSE); + offset++; + + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + { + switch (stream_id) + { + case AUDIO_STREAM_ID: + col_append_str(pinfo->cinfo, COL_INFO, "AUDIO "); + break; + case VIDEO_STREAM_ID: + col_append_str(pinfo->cinfo, COL_INFO, "VIDEO "); + break; + case RETRANSMISSION_REQUEST_STREAM_ID: + col_append_str(pinfo->cinfo, COL_INFO, "Retransmit Request ? "); + break; + default: + col_append_str(pinfo->cinfo, COL_INFO, "Unknown "); + break; + } + } + + if ((stream_id != AUDIO_STREAM_ID) && (stream_id != VIDEO_STREAM_ID)) + { + /* Don't know what to do with others... */ + proto_tree_add_item(rdt_tree, hf_rdt_unparsed, tvb, offset, -1, FALSE); + return; + } + + + /* Sequence number */ + sequence_number = tvb_get_ntohs(tvb, offset); + proto_tree_add_item(rdt_tree, hf_rdt_sequence_number, tvb, offset, 2, FALSE); + offset += 2; + + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + { + col_append_fstr(pinfo->cinfo, COL_INFO, " seq=%d ", sequence_number); + } + + /* These sequence numbers are short packets: give up */ + if ((sequence_number & 0xff00) == 0xff00) + { + proto_tree_add_item(rdt_tree, hf_rdt_unparsed, tvb, offset, -1, FALSE); + return; + } + + /* Packet size (not present if 1st byte's m.s. bit was set) */ + if (stream_id & 0x80) + { + packet_size = tvb_get_ntohs(tvb, offset); + proto_tree_add_item(rdt_tree, hf_rdt_packet_size, tvb, offset, 2, FALSE); + offset += 2; + + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + { + col_append_fstr(pinfo->cinfo, COL_INFO, " size=%d ", packet_size); + } + } + + /* Flags */ + flags = tvb_get_guint8(tvb, offset); + proto_tree_add_item(rdt_tree, hf_rdt_flags, tvb, offset, 1, FALSE); + offset++; + + + /* Timestamp */ + timestamp = tvb_get_ntohl(tvb, offset); + proto_tree_add_item(rdt_tree, hf_rdt_timestamp, tvb, offset, 4, FALSE); + offset += 4; + + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + { + col_append_fstr(pinfo->cinfo, COL_INFO, " ts=%d ", timestamp); + } + + /* The remaining data is unparsed. */ + proto_tree_add_item(rdt_tree, hf_rdt_unparsed, tvb, offset, -1, FALSE); +} + + +/* Look for conversation info and display any setup info found */ +static void show_setup_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + /* Conversation and current data */ + conversation_t *p_conv = NULL; + struct _rdt_conversation_info *p_conv_data = NULL; + + /* Use existing packet info if available */ + p_conv_data = p_get_proto_data(pinfo->fd, proto_rdt); + + if (!p_conv_data) + { + /* First time, get info from conversation */ + p_conv = find_conversation(pinfo->fd->num, &pinfo->net_dst, &pinfo->net_src, + pinfo->ptype, + pinfo->destport, pinfo->srcport, NO_ADDR_B); + if (p_conv) + { + /* Create space for conversation info */ + struct _rdt_conversation_info *p_conv_packet_data; + p_conv_data = conversation_get_proto_data(p_conv, proto_rdt); + + if (p_conv_data) + { + /* Save this conversation info into packet info */ + p_conv_packet_data = g_mem_chunk_alloc(rdt_conversations); + strcpy(p_conv_packet_data->method, p_conv_data->method); + p_conv_packet_data->frame_number = p_conv_data->frame_number; + p_add_proto_data(pinfo->fd, proto_rdt, p_conv_packet_data); + } + } + } + + /* Create setup info subtree with summary info. */ + if (p_conv_data) + { + proto_tree *rdt_setup_tree; + proto_item *ti = proto_tree_add_string_format(tree, hf_rdt_setup, tvb, 0, 0, + "", + "Stream setup by %s (frame %d)", + p_conv_data->method, + p_conv_data->frame_number); + PROTO_ITEM_SET_GENERATED(ti); + rdt_setup_tree = proto_item_add_subtree(ti, ett_rdt_setup); + if (rdt_setup_tree) + { + /* Add details into subtree */ + proto_item* item = proto_tree_add_uint(rdt_setup_tree, hf_rdt_setup_frame, + tvb, 0, 0, p_conv_data->frame_number); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_string(rdt_setup_tree, hf_rdt_setup_method, + tvb, 0, 0, p_conv_data->method); + PROTO_ITEM_SET_GENERATED(item); + } + } +} + + +void +proto_register_rdt(void) +{ + static hf_register_info hf[] = + { + { + &hf_rdt_stream_id, + { + "StreamID", + "rdt.stream_id", + FT_UINT8, + BASE_DEC, + VALS(rdt_stream_id_vals), + 0x0, + "", HFILL + } + }, + { + &hf_rdt_sequence_number, + { + "Sequence number", + "rdt.sequence_number", + FT_UINT16, + BASE_DEC, + NULL, + 0x0, + "", HFILL + } + }, + { + &hf_rdt_flags, + { + "Flags", + "rdt.flags", + FT_UINT8, + BASE_DEC, + NULL, + 0x0, + "", HFILL + } + }, + { + &hf_rdt_packet_size, + { + "Packet size", + "rdt.packet_size", + FT_UINT16, + BASE_DEC, + NULL, + 0x0, + "", HFILL + } + }, + { + &hf_rdt_timestamp, + { + "Timestamp", + "rdt.timestamp", + FT_UINT32, + BASE_DEC, + NULL, + 0x0, + "Timestamp", HFILL + } + }, + { + &hf_rdt_setup, + { + "Stream setup", + "rdt.setup", + FT_STRING, + BASE_NONE, + NULL, + 0x0, + "Stream setup, method and frame number", HFILL + } + }, + { + &hf_rdt_setup_frame, + { + "Setup frame", + "rdt.setup-frame", + FT_FRAMENUM, + BASE_NONE, + NULL, + 0x0, + "Frame that set up this stream", HFILL + } + }, + { + &hf_rdt_setup_method, + { + "Setup Method", + "rdt.setup-method", + FT_STRING, + BASE_NONE, + NULL, + 0x0, + "Method used to set up this stream", HFILL + } + }, + { + &hf_rdt_unparsed, + { + "Unparsed Data", + "rdt.unparsed", + FT_NONE, + BASE_NONE, + NULL, + 0x0, + "", HFILL + } + } + }; + + static gint *ett[] = + { + &ett_rdt, + &ett_rdt_setup + }; + + module_t *rdt_module; + + /* Register protocol and fields */ + proto_rdt = proto_register_protocol("Real Data Transport", "RDT", "rdt"); + proto_register_field_array(proto_rdt, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + register_dissector("rdt", dissect_rdt, proto_rdt); + + /* Preference settings */ + rdt_module = prefs_register_protocol(proto_rdt, NULL); + prefs_register_bool_preference(rdt_module, "show_setup_info", + "Show stream setup information", + "Where available, show which protocol and frame caused " + "this RDT stream to be created", + &global_rdt_show_setup_info); + + register_init_routine( &rdt_init ); +} + +void +proto_reg_handoff_rdt(void) +{ + rdt_handle = find_dissector("rdt"); +} +
diff --git a/epan/dissectors/packet-rdt.h b/epan/dissectors/packet-rdt.h new file mode 100644 index 0000000000..3a6a193834 --- /dev/null +++ b/epan/dissectors/packet-rdt.h @@ -0,0 +1,42 @@ +/* packet-rdt.h + * + * Routines for RDT dissection + * RDT = Real Data Transport + * + * $Id: packet-rdt.h 13300 2005-02-05 11:08:24Z etxrab $ + * + * Written by Martin Mathieson + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@ethereal.com> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Info to save in RDT conversation / packet-info */ +#define MAX_RDT_SETUP_METHOD_SIZE 7 +struct _rdt_conversation_info +{ + gchar method[MAX_RDT_SETUP_METHOD_SIZE + 1]; + guint32 frame_number; +}; + +/* Add an RDT conversation with the given details */ +void rdt_add_address(packet_info *pinfo, + address *addr, int port, + int other_port, + gchar *setup_method, guint32 setup_frame_number); +
diff --git a/epan/dissectors/packet-rtsp.c b/epan/dissectors/packet-rtsp.c index 78b7d38e0a..3307c625a8 100644 --- a/epan/dissectors/packet-rtsp.c +++ b/epan/dissectors/packet-rtsp.c @@ -42,6 +42,7 @@ #include <epan/req_resp_hdrs.h> #include "packet-rtp.h" #include "packet-rtcp.h" +#include "packet-rdt.h" #include <epan/conversation.h> #include <epan/strutil.h> #include "packet-e164.h" @@ -341,6 +342,7 @@ static const char rtsp_transport[] = "Transport:"; static const char rtsp_sps[] = "server_port="; static const char rtsp_cps[] = "client_port="; static const char rtsp_rtp[] = "rtp/"; +static const char rtsp_real_rdt[] = "x-real-rdt/"; static const char rtsp_inter[] = "interleaved="; static void @@ -350,6 +352,8 @@ rtsp_create_conversation(packet_info *pinfo, const guchar *line_begin, conversation_t *conv; guchar buf[256]; guchar *tmp; + gboolean rtp_transport = FALSE; + gboolean rdt_transport = FALSE; guint c_data_port, c_mon_port; guint s_data_port, s_mon_port; @@ -362,16 +366,27 @@ rtsp_create_conversation(packet_info *pinfo, const guchar *line_begin, memcpy(buf, line_begin, line_len); buf[line_len] = '\0'; + /* Get past "Transport:" and spaces */ tmp = buf + STRLEN_CONST(rtsp_transport); while (*tmp && isspace(*tmp)) tmp++; - if (strncasecmp(tmp, rtsp_rtp, strlen(rtsp_rtp)) != 0) { + + /* Work out which transport type is here */ + if (strncasecmp(tmp, rtsp_rtp, strlen(rtsp_rtp)) == 0) + rtp_transport = TRUE; + else + if (strncasecmp(tmp, rtsp_real_rdt, strlen(rtsp_real_rdt)) == 0) + rdt_transport = TRUE; + else + { g_warning("Frame %u: rtsp: unknown transport %s", pinfo->fd->num, tmp); return; } - + c_data_port = c_mon_port = 0; s_data_port = s_mon_port = 0; + + /* Look for server port */ if ((tmp = strstr(buf, rtsp_sps))) { tmp += strlen(rtsp_sps); if (sscanf(tmp, "%u-%u", &s_data_port, &s_mon_port) < 1) { @@ -380,6 +395,7 @@ rtsp_create_conversation(packet_info *pinfo, const guchar *line_begin, return; } } + /* Look for client port */ if ((tmp = strstr(buf, rtsp_cps))) { tmp += strlen(rtsp_cps); if (sscanf(tmp, "%u-%u", &c_data_port, &c_mon_port) < 1) { @@ -422,13 +438,17 @@ rtsp_create_conversation(packet_info *pinfo, const guchar *line_begin, data = g_mem_chunk_alloc(rtsp_vals); conversation_add_proto_data(conv, proto_rtsp, data); } - if (s_data_chan < RTSP_MAX_INTERLEAVED) { - data->interleaved[s_data_chan].dissector = - rtp_handle; - } - if (i > 1 && s_mon_chan < RTSP_MAX_INTERLEAVED) { - data->interleaved[s_mon_chan].dissector = - rtcp_handle; + + if (rtp_transport) + { + if (s_data_chan < RTSP_MAX_INTERLEAVED) { + data->interleaved[s_data_chan].dissector = + rtp_handle; + } + if (i > 1 && s_mon_chan < RTSP_MAX_INTERLEAVED) { + data->interleaved[s_mon_chan].dissector = + rtcp_handle; + } } return; } @@ -440,14 +460,23 @@ rtsp_create_conversation(packet_info *pinfo, const guchar *line_begin, * sent the packet, so we construct a conversation with no * second address. */ - rtp_add_address(pinfo, &pinfo->dst, c_data_port, s_data_port, - "RTSP", pinfo->fd->num); - - if (!c_mon_port) - return; - - rtcp_add_address(pinfo, &pinfo->dst, c_mon_port, s_mon_port, - "RTSP", pinfo->fd->num); + if (rtp_transport) + { + rtp_add_address(pinfo, &pinfo->dst, c_data_port, s_data_port, + "RTSP", pinfo->fd->num); + + if (!c_mon_port) + return; + + rtcp_add_address(pinfo, &pinfo->dst, c_mon_port, s_mon_port, + "RTSP", pinfo->fd->num); + } + else + if (rdt_transport) + { + rdt_add_address(pinfo, &pinfo->dst, c_data_port, s_data_port, + "RTSP", pinfo->fd->num); + } } static const char rtsp_content_length[] = "Content-Length:"; |