SDP/RTP: Support for "bundled" media.

Modern SDP usage (e.g. SIP, WebRTC) can "bundle" multiple RTP media streams on
a single port. Thus the RTP dissector has to be able to handle audio and video
at the same time, so the gboolean flag in _rtp_info was changed to a bit mask.
The SDP parsing was then changed to detect multiple "m=" lines using the same
port, and combine their audio/video bit masks, and the rtp_dyn_payload used
has all the audio and video payload descriptions.

Change-Id: Ifa3c034260f892ed005fe28647d28f3b0b1b05cf
Reviewed-on: https://code.wireshark.org/review/25431
Petri-Dish: Jaap Keuter <jaap.keuter@xs4all.nl>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
Robert Jongbloed 2018-01-23 12:13:43 +00:00 committed by Anders Broman
parent d328a58fc6
commit 94d7500a7d
5 changed files with 86 additions and 32 deletions

View File

@ -3076,7 +3076,7 @@ dissect_bta2dp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
if (bta2dp_codec_info.content_protection_type == 0 && codec_dissector == aptx_handle) {
call_dissector_with_data(aptx_handle, tvb, pinfo, tree, &bta2dp_codec_info);
} else {
bluetooth_add_address(pinfo, &pinfo->net_dst, sep_data.stream_number, "BT A2DP", pinfo->num, FALSE, &bta2dp_codec_info);
bluetooth_add_address(pinfo, &pinfo->net_dst, sep_data.stream_number, "BT A2DP", pinfo->num, RTP_MEDIA_AUDIO, &bta2dp_codec_info);
call_dissector(rtp_handle, tvb, pinfo, tree);
}
offset += tvb_reported_length_remaining(tvb, offset);
@ -3309,7 +3309,7 @@ dissect_btvdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
pinfo->destport = sep_data.stream_number;
#endif
bluetooth_add_address(pinfo, &pinfo->net_dst, 0, "BT VDP", pinfo->num, TRUE, &btvdp_codec_info);
bluetooth_add_address(pinfo, &pinfo->net_dst, 0, "BT VDP", pinfo->num, RTP_MEDIA_VIDEO, &btvdp_codec_info);
call_dissector(rtp_handle, tvb, pinfo, tree);
offset += tvb_reported_length_remaining(tvb, offset);

View File

@ -1181,7 +1181,7 @@ rtp_dyn_payload_free(rtp_dyn_payload_t *rtp_dyn_payload)
void
bluetooth_add_address(packet_info *pinfo, address *addr, guint32 stream_number,
const gchar *setup_method, guint32 setup_frame_number,
gboolean is_video, void *data)
guint32 media_types, void *data)
{
address null_addr;
conversation_t* p_conv;
@ -1237,13 +1237,10 @@ bluetooth_add_address(packet_info *pinfo, address *addr, guint32 stream_number,
p_conv_data->rtp_conv_info->multisegment_pdus = wmem_tree_new(wmem_file_scope());
conversation_add_proto_data(p_conv, proto_rtp, p_conv_data);
if (is_video) {
p_conv_data->bta2dp_info = NULL;
p_conv_data->btvdp_info = (btvdp_codec_info_t *) wmem_memdup(wmem_file_scope(), data, sizeof(btvdp_codec_info_t));
} else {
if (media_types&RTP_MEDIA_AUDIO)
p_conv_data->bta2dp_info = (bta2dp_codec_info_t *) wmem_memdup(wmem_file_scope(), data, sizeof(bta2dp_codec_info_t));
p_conv_data->btvdp_info = NULL;
}
if (media_types&RTP_MEDIA_VIDEO)
p_conv_data->btvdp_info = (btvdp_codec_info_t *) wmem_memdup(wmem_file_scope(), data, sizeof(btvdp_codec_info_t));
}
/*
@ -1254,7 +1251,7 @@ bluetooth_add_address(packet_info *pinfo, address *addr, guint32 stream_number,
g_strlcpy(p_conv_data->method, setup_method, MAX_RTP_SETUP_METHOD_SIZE+1);
p_conv_data->frame_number = setup_frame_number;
p_conv_data->is_video = is_video;
p_conv_data->media_types = media_types;
p_conv_data->rtp_dyn_payload = NULL;
p_conv_data->srtp_info = NULL;
}
@ -1263,7 +1260,7 @@ bluetooth_add_address(packet_info *pinfo, address *addr, guint32 stream_number,
void
srtp_add_address(packet_info *pinfo, const port_type ptype, address *addr, int port, int other_port,
const gchar *setup_method, guint32 setup_frame_number,
gboolean is_video _U_, rtp_dyn_payload_t *rtp_dyn_payload,
guint32 media_types _U_, rtp_dyn_payload_t *rtp_dyn_payload,
struct srtp_info *srtp_info)
{
address null_addr;
@ -1359,7 +1356,7 @@ srtp_add_address(packet_info *pinfo, const port_type ptype, address *addr, int p
g_strlcpy(p_conv_data->method, setup_method, MAX_RTP_SETUP_METHOD_SIZE+1);
p_conv_data->frame_number = setup_frame_number;
p_conv_data->is_video = is_video;
p_conv_data->media_types = media_types;
p_conv_data->srtp_info = srtp_info;
p_conv_data->bta2dp_info = NULL;
p_conv_data->btvdp_info = NULL;
@ -1369,9 +1366,9 @@ srtp_add_address(packet_info *pinfo, const port_type ptype, address *addr, int p
void
rtp_add_address(packet_info *pinfo, const port_type ptype, address *addr, int port, int other_port,
const gchar *setup_method, guint32 setup_frame_number,
gboolean is_video , rtp_dyn_payload_t *rtp_dyn_payload)
guint32 media_types , rtp_dyn_payload_t *rtp_dyn_payload)
{
srtp_add_address(pinfo, ptype, addr, port, other_port, setup_method, setup_frame_number, is_video, rtp_dyn_payload, NULL);
srtp_add_address(pinfo, ptype, addr, port, other_port, setup_method, setup_frame_number, media_types, rtp_dyn_payload, NULL);
}
static gboolean
@ -1441,7 +1438,7 @@ dissect_rtp_heur_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, voi
}
g_strlcpy(p_conv_data->method, "HEUR RTP", MAX_RTP_SETUP_METHOD_SIZE+1);
p_conv_data->frame_number = pinfo->num;
p_conv_data->is_video = FALSE;
p_conv_data->media_types = 0;
p_conv_data->srtp_info = NULL;
p_conv_data->bta2dp_info = NULL;
p_conv_data->btvdp_info = NULL;
@ -2127,7 +2124,7 @@ dissect_rtp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_
rtp_info->info_padding_set = padding_set;
rtp_info->info_padding_count = 0;
rtp_info->info_marker_set = marker_set;
rtp_info->info_is_video = FALSE;
rtp_info->info_media_types = 0;
rtp_info->info_payload_type = payload_type;
rtp_info->info_seq_num = seq_num;
rtp_info->info_timestamp = timestamp;
@ -2176,7 +2173,7 @@ dissect_rtp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_
p_conv_data = get_conv_info(pinfo, rtp_info);
if (p_conv_data)
rtp_info->info_is_video = p_conv_data->is_video;
rtp_info->info_media_types = p_conv_data->media_types;
if (p_conv_data && p_conv_data->srtp_info) is_srtp = TRUE;
rtp_info->info_is_srtp = is_srtp;
@ -2788,7 +2785,7 @@ get_conv_info(packet_info *pinfo, struct _rtp_info *rtp_info)
p_conv_packet_data = wmem_new(wmem_file_scope(), struct _rtp_conversation_info);
g_strlcpy(p_conv_packet_data->method, p_conv_data->method, MAX_RTP_SETUP_METHOD_SIZE+1);
p_conv_packet_data->frame_number = p_conv_data->frame_number;
p_conv_packet_data->is_video = p_conv_data->is_video;
p_conv_packet_data->media_types = p_conv_data->media_types;
/* do not increment ref count for the rtp_dyn_payload */
p_conv_packet_data->rtp_dyn_payload = p_conv_data->rtp_dyn_payload;
p_conv_packet_data->rtp_conv_info = p_conv_data->rtp_conv_info;

View File

@ -30,11 +30,16 @@
#include "packet-btavdtp.h"
#define RTP_MEDIA_AUDIO 1
#define RTP_MEDIA_VIDEO 2
#define RTP_MEDIA_OTHER 4
struct _rtp_info {
unsigned int info_version;
gboolean info_padding_set;
gboolean info_marker_set;
gboolean info_is_video;
guint32 info_media_types;
unsigned int info_payload_type;
unsigned int info_padding_count;
guint16 info_seq_num;
@ -177,7 +182,7 @@ struct _rtp_conversation_info
{
gchar method[MAX_RTP_SETUP_METHOD_SIZE + 1];
guint32 frame_number; /* the frame where this conversation is started */
gboolean is_video;
guint32 media_types;
rtp_dyn_payload_t *rtp_dyn_payload; /* the dynamic RTP payload info - see comments above */
guint32 extended_seqno; /* the sequence number, extended to a 32-bit
@ -200,7 +205,7 @@ void rtp_add_address(packet_info *pinfo,
int other_port,
const gchar *setup_method,
guint32 setup_frame_number,
gboolean is_video,
guint32 media_types,
rtp_dyn_payload_t *rtp_dyn_payload);
/* Add an SRTP conversation with the given details */
@ -211,7 +216,7 @@ void srtp_add_address(packet_info *pinfo,
int other_port,
const gchar *setup_method,
guint32 setup_frame_number,
gboolean is_video,
guint32 media_types,
rtp_dyn_payload_t *rtp_dyn_payload,
struct srtp_info *srtp_info);
@ -219,4 +224,4 @@ void srtp_add_address(packet_info *pinfo,
void
bluetooth_add_address(packet_info *pinfo, address *addr, guint32 stream_number,
const gchar *setup_method, guint32 setup_frame_number,
gboolean is_video, void *data);
guint32 media_types, void *data);

View File

@ -248,7 +248,8 @@ typedef struct {
*/
typedef struct {
transport_proto_t proto; /**< Protocol, parsed from "m=" line. */
gboolean is_video; /**< Whether "m=video" */
guint32 media_types; /**< Whether "m=video" or others */
gboolean bundled; /**< "m=" lines are "bundled", that is, all on same port */
guint16 media_port; /**< Port number, parsed from "m=" line. */
guint16 control_port; /**< Port number, parsed from "a=rtcp" or "a=rtcp-mux" line. */
address conn_addr; /**< The address from the "c=" line (default
@ -1026,7 +1027,12 @@ dissect_sdp_media(tvbuff_t *tvb, packet_info* pinfo, proto_item *ti,
ENC_UTF_8|ENC_NA, wmem_packet_scope(), &media_type_str);
if (media_desc) {
/* for RTP statistics (supposedly?) */
media_desc->is_video = strcmp(media_type_str, "video") == 0;
if (strcmp(media_type_str, "audio") == 0)
media_desc->media_types |= RTP_MEDIA_AUDIO;
else if (strcmp(media_type_str, "video") == 0)
media_desc->media_types |= RTP_MEDIA_VIDEO;
else
media_desc->media_types |= RTP_MEDIA_OTHER;
}
DPRINT(("parsed media_type=%s", media_type_str));
@ -2101,13 +2107,49 @@ complete_descriptions(transport_info_t *transport_info, guint answer_offset)
{
guint media_count = wmem_array_get_count(transport_info->media_descriptions);
media_description_t *media_descs = (media_description_t *)wmem_array_get_raw(transport_info->media_descriptions);
media_description_t *bundle_media_desc = NULL;
DPRINT(("complete_descriptions called with answer_offset=%d media_count=%d",
answer_offset, media_count));
for (guint i = answer_offset; i < media_count && !bundle_media_desc; i++) {
for (guint j = i+1; j < media_count && !bundle_media_desc; j++) {
if (media_descs[i].media_port == media_descs[j].media_port)
bundle_media_desc = &media_descs[i];
}
}
if (bundle_media_desc) {
/* We have "bundling" of media, so now combine all the media bit masks
and merge the rtp_dyn_payload so that the first media description
has all the data for every media desciption. */
for (guint i = answer_offset; i < media_count; i++) {
media_description_t *media_desc = &media_descs[i];
if (bundle_media_desc->media_port == media_desc->media_port) {
media_desc->bundled = TRUE;
if (media_desc != bundle_media_desc) {
bundle_media_desc->media_types |= media_desc->media_types;
for (guint pt = 0; pt < 128; ++pt) {
const char * encoding_name;
int sample_rate;
if (rtp_dyn_payload_get_full(media_desc->media.rtp_dyn_payload,
pt, &encoding_name, &sample_rate))
rtp_dyn_payload_insert(bundle_media_desc->media.rtp_dyn_payload,
pt, encoding_name, sample_rate);
}
}
}
}
}
for (guint i = answer_offset; i < media_count; i++) {
media_description_t *media_desc = &media_descs[i];
if (media_desc->control_port == 0)
media_desc->control_port = media_desc->media_port + 1;
if (media_desc->control_port == 0)
media_desc->control_port = media_desc->media_port + 1;
@ -2169,6 +2211,8 @@ apply_sdp_transport(packet_info *pinfo, transport_info_t *transport_info, int re
establish_frame = request_frame;
}
gboolean bundled_media_set = FALSE;
for (guint i = 0; i < wmem_array_get_count(transport_info->media_descriptions); i++) {
media_description_t *media_desc =
(media_description_t *)wmem_array_index(transport_info->media_descriptions, i);
@ -2176,11 +2220,20 @@ apply_sdp_transport(packet_info *pinfo, transport_info_t *transport_info, int re
/* Add (s)rtp and (s)rtcp conversation, if available (overrides t38 if conversation already set) */
if ((media_desc->media_port != 0) &&
!media_desc->media.set_rtp &&
(media_desc->proto == SDP_PROTO_RTP ||
media_desc->proto == SDP_PROTO_SRTP) &&
(media_desc->conn_addr.type == AT_IPv4 ||
media_desc->conn_addr.type == AT_IPv6)) {
media_desc->media.set_rtp = TRUE;
if (media_desc->bundled) {
if (bundled_media_set)
continue;
bundled_media_set = TRUE;
}
if (media_desc->proto == SDP_PROTO_SRTP) {
srtp_info = wmem_new0(wmem_file_scope(), struct srtp_info);
if (transport_info->encryption_algorithm != SRTP_ENC_ALG_NOT_SET) {
@ -2196,7 +2249,7 @@ apply_sdp_transport(packet_info *pinfo, transport_info_t *transport_info, int re
/* srtp_add_address and rtp_add_address are given the request_frame's not this frame's number,
because that's where the RTP flow started, and thus conversation needs to check against */
srtp_add_address(pinfo, PT_UDP, &media_desc->conn_addr, media_desc->media_port, 0, "SDP", establish_frame,
media_desc->is_video,
media_desc->media_types,
media_desc->media.rtp_dyn_payload, srtp_info);
DENDENT();
} else {
@ -2204,23 +2257,22 @@ apply_sdp_transport(packet_info *pinfo, transport_info_t *transport_info, int re
i, media_desc->media_port));
DINDENT();
rtp_add_address(pinfo, PT_UDP, &media_desc->conn_addr, media_desc->media_port, 0, "SDP", establish_frame,
media_desc->is_video,
media_desc->media_types,
media_desc->media.rtp_dyn_payload);
DENDENT();
}
media_desc->media.set_rtp = TRUE;
/* SPRT might use the same port... */
current_rtp_port = media_desc->media_port;
if (rtcp_handle && media_desc->media_port != media_desc->control_port) {
if (media_desc->proto == SDP_PROTO_SRTP) {
DPRINT(("calling rtcp_add_address, channel=%d, media_port=%d",
DPRINT(("calling rtcp_add_address, channel=%d, control_port=%d",
i, media_desc->control_port));
DINDENT();
srtcp_add_address(pinfo, &media_desc->conn_addr, media_desc->control_port, 0, "SDP", establish_frame, srtp_info);
DENDENT();
} else {
DPRINT(("calling rtcp_add_address, channel=%d, media_port=%d",
DPRINT(("calling rtcp_add_address, channel=%d, control_port=%d",
i, media_desc->control_port));
DINDENT();
rtcp_add_address(pinfo, &media_desc->conn_addr, media_desc->control_port, 0, "SDP", establish_frame);

View File

@ -455,10 +455,10 @@ dissect_Conf2ACK(packet_info *pinfo) {
dummy_srtp_info->auth_tag_len = 4;
srtp_add_address(pinfo, PT_UDP, &pinfo->net_src, pinfo->srcport, pinfo->destport,
"ZRTP", pinfo->num, FALSE, NULL, dummy_srtp_info);
"ZRTP", pinfo->num, RTP_MEDIA_AUDIO, NULL, dummy_srtp_info);
srtp_add_address(pinfo, PT_UDP, &pinfo->net_dst, pinfo->destport, pinfo->srcport,
"ZRTP", pinfo->num, FALSE, NULL, dummy_srtp_info);
"ZRTP", pinfo->num, RTP_MEDIA_AUDIO, NULL, dummy_srtp_info);
srtcp_add_address(pinfo, &pinfo->net_src, pinfo->srcport+1, pinfo->destport+1,
"ZRTP", pinfo->num, dummy_srtp_info);