* Jason Lango <jal@netapp.com>
* Liberally copied from packet-http.c, by Guy Harris <guy@alum.mit.edu>
*
- * $Id: packet-sdp.c,v 1.39 2003/12/07 03:46:04 guy Exp $
+ * $Id$
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
#include <epan/conversation.h>
#include <epan/strutil.h>
+#include "packet-rtp.h"
+#include "rtp_pt.h"
+#include "packet-rtcp.h"
+
+
static dissector_handle_t rtp_handle=NULL;
static dissector_handle_t rtcp_handle=NULL;
static int ett_sdp_media = -1;
static int ett_sdp_media_attribute = -1;
+
+#define SDP_MAX_RTP_CHANNELS 4
+
typedef struct {
- char *media_port;
- char *media_proto;
char *connection_address;
char *connection_type;
+ char *media_port[SDP_MAX_RTP_CHANNELS];
+ char *media_proto[SDP_MAX_RTP_CHANNELS];
+ gint8 media_count;
} transport_info_t;
/* static functions */
char *string;
address src_addr;
- conversation_t *conv=NULL;
transport_info_t transport_info;
+
guint32 ipv4_address=0;
guint32 ipv4_port=0;
gboolean is_rtp=FALSE;
gboolean is_ipv4_addr=FALSE;
struct in_addr ipaddr;
+ gint n;
- transport_info.media_port=NULL;
- transport_info.media_proto=NULL;
+ /* Initialise RTP channel info */
transport_info.connection_address=NULL;
transport_info.connection_type=NULL;
+ for (n=0; n < SDP_MAX_RTP_CHANNELS; n++)
+ {
+ transport_info.media_port[n]=NULL;
+ transport_info.media_proto[n]=NULL;
+ }
+ transport_info.media_count = 0;
+
/*
* As RFC 2327 says, "SDP is purely a format for session
* Show the SDP message a line at a time.
*/
in_media_description = FALSE;
- while (tvb_offset_exists(tvb, offset)) {
+ while (tvb_reported_length_remaining(tvb, offset) > 0) {
/*
* Find the end of the line.
*/
linelen - tokenoffset));
g_free(string);
call_sdp_subdissector(tvb_new_subset(tvb,offset+tokenoffset,
- linelen-tokenoffset,-1),
+ linelen-tokenoffset,
+ linelen-tokenoffset),
hf,sub_ti,&transport_info),
offset = next_offset;
}
/* Now look, if we have strings collected.
- * Try to convert ipv4 address and port into binary format,
+ * Try to convert ipv4 addresses and ports into binary format,
* so we can use them to detect rtp and rtcp streams.
* Don't forget to free the strings!
*/
- if(transport_info.media_port!=NULL) {
- ipv4_port = atol(transport_info.media_port);
- g_free(transport_info.media_port);
- }
- if(transport_info.media_proto!=NULL) {
- /* Check if media protocol is RTP */
- is_rtp = (strcmp(transport_info.media_proto,"RTP/AVP")==0);
- g_free(transport_info.media_proto);
+ for (n = 0; n < transport_info.media_count; n++)
+ {
+ if(transport_info.media_port[n]!=NULL) {
+ ipv4_port = atol(transport_info.media_port[n]);
+ g_free(transport_info.media_port[n]);
+ }
+ if(transport_info.media_proto[n]!=NULL) {
+ /* Check if media protocol is RTP */
+ is_rtp = (strcmp(transport_info.media_proto[n],"RTP/AVP")==0);
+ g_free(transport_info.media_proto[n]);
+ }
+ if(transport_info.connection_address!=NULL) {
+ if(transport_info.connection_type!=NULL &&
+ strcmp(transport_info.connection_type,"IP4")==0) {
+ if(inet_aton(transport_info.connection_address, &ipaddr)
+ !=0 ) {
+ /* connection_address could be converted to a valid ipv4 address*/
+ is_ipv4_addr=TRUE;
+ ipv4_address = ipaddr.s_addr;
+ }
+ }
+ }
+
+ /* Add rtp and rtcp conversation, if available */
+ if((!pinfo->fd->flags.visited) && ipv4_address!=0 && ipv4_port!=0 && is_rtp && is_ipv4_addr){
+ src_addr.type=AT_IPv4;
+ src_addr.len=4;
+ src_addr.data=(char *)&ipv4_address;
+
+ if(rtp_handle){
+ rtp_add_address(pinfo, (char *)&ipv4_address, ipv4_port, 0,
+ "SDP", pinfo->fd->num);
+ }
+
+ if(rtcp_handle){
+ ipv4_port++;
+ rtcp_add_address(pinfo, (char *)&ipv4_address, ipv4_port, 0,
+ "SDP", pinfo->fd->num);
+ }
+ }
}
- if(transport_info.connection_address!=NULL) {
- if(transport_info.connection_type!=NULL &&
- strcmp(transport_info.connection_type,"IP4")==0) {
- if(inet_aton(transport_info.connection_address, &ipaddr)
- !=0 ) {
- /* connection_address could be converted to a valid ipv4 address*/
- is_ipv4_addr=TRUE;
- ipv4_address = ipaddr.s_addr;
- }
- }
+
+ /* Free up 'connection info' strings */
+ if(transport_info.connection_address) {
g_free(transport_info.connection_address);
}
if(transport_info.connection_type!=NULL) {
g_free(transport_info.connection_type);
}
- /* Add rtp and rtcp conversation, if available */
- if((!pinfo->fd->flags.visited) && ipv4_address!=0 && ipv4_port!=0 && is_rtp && is_ipv4_addr){
- src_addr.type=AT_IPv4;
- src_addr.len=4;
- src_addr.data=(char *)&ipv4_address;
-
- if(rtp_handle){
- conv=find_conversation(&src_addr, &src_addr, PT_UDP, ipv4_port, ipv4_port, NO_ADDR_B|NO_PORT_B);
- if(!conv){
- conv=conversation_new(&src_addr, &src_addr, PT_UDP, ipv4_port, ipv4_port, NO_ADDR_B|NO_PORT_B);
- conversation_set_dissector(conv, rtp_handle);
- }
- }
-
- if(rtcp_handle){
- ipv4_port++;
- conv=find_conversation(&src_addr, &src_addr, PT_UDP, ipv4_port, ipv4_port, NO_ADDR_B|NO_PORT_B);
- if(!conv){
- conv=conversation_new(&src_addr, &src_addr, PT_UDP, ipv4_port, ipv4_port, NO_ADDR_B|NO_PORT_B);
- conversation_set_dissector(conv, rtcp_handle);
- }
- }
- }
datalen = tvb_length_remaining(tvb, offset);
if (datalen > 0) {
proto_tree_add_item(sdp_owner_tree,hf_owner_address, tvb, offset, -1, FALSE);
}
+/*
+ * XXX - this can leak memory if an exception is thrown after we've fetched
+ * a string.
+ */
static void
dissect_sdp_connection_info(tvbuff_t *tvb, proto_item* ti,
transport_info_t *transport_info){
/* Save connection address type */
transport_info->connection_type = tvb_get_string(tvb, offset, tokenlen);
+
proto_tree_add_item(sdp_connection_info_tree,
hf_connection_info_address_type,tvb,
offset,tokenlen,FALSE);
/* get stop time */
offset = next_offset + 1;
- proto_tree_add_item(sdp_time_tree,hf_time_start, tvb,
+ proto_tree_add_item(sdp_time_tree, hf_time_stop, tvb,
offset, -1, FALSE);
}
transport_info_t *transport_info){
proto_tree *sdp_media_tree;
gint offset, next_offset, tokenlen;
+ guint8 *media_format;
offset = 0;
next_offset = 0;
if(next_offset != -1){
tokenlen = next_offset - offset;
/* Save port info */
- transport_info->media_port = tvb_get_string(tvb, offset, tokenlen);
+ transport_info->media_port[transport_info->media_count] = tvb_get_string(tvb, offset, tokenlen);
proto_tree_add_item(sdp_media_tree, hf_media_port, tvb,
offset, tokenlen, FALSE);
return;
tokenlen = next_offset - offset;
/* Save port info */
- transport_info->media_port = tvb_get_string(tvb, offset, tokenlen);
+ transport_info->media_port[transport_info->media_count] = tvb_get_string(tvb, offset, tokenlen);
/* XXX Remember Port */
proto_tree_add_item(sdp_media_tree, hf_media_port, tvb,
tokenlen = next_offset - offset;
/* Save port protocol */
- transport_info->media_proto = tvb_get_string(tvb, offset, tokenlen);
+ transport_info->media_proto[transport_info->media_count] = tvb_get_string(tvb, offset, tokenlen);
/* XXX Remember Protocol */
proto_tree_add_item(sdp_media_tree, hf_media_proto, tvb,
next_offset = tvb_find_guint8(tvb,offset,-1,' ');
if(next_offset == -1){
- tokenlen = -1; /* End of tvbuff */
+ tokenlen = tvb_length_remaining(tvb, offset); /* End of tvbuff */
+ if (tokenlen == 0)
+ break; /* Nothing more left */
} else {
tokenlen = next_offset - offset;
}
- proto_tree_add_item(sdp_media_tree, hf_media_format, tvb,
- offset, tokenlen, FALSE);
+ media_format = tvb_get_string(tvb, offset, tokenlen);
+ if (!strcmp(transport_info->media_proto[transport_info->media_count], "RTP/AVP")) {
+ proto_tree_add_string(sdp_media_tree, hf_media_format, tvb,
+ offset, tokenlen, val_to_str(atol(media_format), rtp_payload_type_vals, "%u"));
+ } else {
+ proto_tree_add_item(sdp_media_tree, hf_media_format, tvb,
+ offset, tokenlen, FALSE);
+ }
} while (next_offset != -1);
+ /* Increase the count of media channels, but don't walk off the end
+ of the arrays. */
+ if (transport_info->media_count < (SDP_MAX_RTP_CHANNELS-1)){
+ transport_info->media_count++;
+ }
+
/* XXX Dissect traffic to "Port" as "Protocol"
* Remember this Port/Protocol pair so we can tear it down again later
* Actually, it's harder than that:
{ &hf_bandwidth_value,
{ "Bandwidth Value",
"sdp.bandwidth.value",FT_STRING, BASE_NONE, NULL, 0x0,
- "Bandwidth Value", HFILL }},
+ "Bandwidth Value (in kbits/s)", HFILL }},
{ &hf_time_start,
{ "Session Start Time",
"sdp.time.start",FT_STRING, BASE_NONE, NULL, 0x0,
{ &hf_media_proto,
{ "Media Proto",
"sdp.media.proto",FT_STRING, BASE_NONE, NULL, 0x0,
- "Media Proto", HFILL }},
+ "Media Protocol", HFILL }},
{ &hf_media_format,
{ "Media Format",
"sdp.media.format",FT_STRING, BASE_NONE, NULL, 0x0,