forked from osmocom/wireshark
Bluetooth AVDTP/RTP: Separate the streams
The Stream is defined here as media stream that beginning on AVDTP Start (ResponseAccept). Also fix recognizing Channel streams by AVDTP according to the specification that says: 1. First channel is always Signaling. 2. Second may be Media. 3. Third may be Reporting. 4. Fourth may be Recovery. First and second will be supported right now. Change-Id: Id6d4dae6be1b9df68382288c2d520b7ed3661237 Reviewed-on: https://code.wireshark.org/review/1053 Reviewed-by: Michal Labedzki <michal.labedzki@tieto.com>
This commit is contained in:
parent
32e66a4cc6
commit
2abc54158d
|
@ -100,6 +100,34 @@
|
|||
#define SEP_MAX 64
|
||||
#define SEP_SIZE 2
|
||||
|
||||
/* ========================================================== */
|
||||
/* Story: RTP Player, conversation (probably reassemble too) use address:port as
|
||||
"key" to separate devices/streams. In Bluetooth World it is not enough to
|
||||
separate devices/streams. Example key:
|
||||
guint32 interface_id (aka frame.interface_id)
|
||||
guint32 adapter_id (interface like "bluetooth-monitor" or USB provide
|
||||
more than one device over interface, so we must
|
||||
separate information provided by each one)
|
||||
guint16 hci_chandle (aka "connection handle" use to separate connections to devices)
|
||||
guint16 l2cap_psm (like hci_chandle but over l2cap layer, need hci_chandle info because
|
||||
the same PSM can be used over chandles)
|
||||
guint8 rfcomm_channel (like l2cap_psm, but over RFCOMM layer...)
|
||||
etc. like
|
||||
guint8 stram_endpoint_number
|
||||
guint32 stream_number (to separate multiple streams for RTP Player)
|
||||
|
||||
So keys can be various (length or type) and "ports" are not enough to sore
|
||||
all needed information. If one day that changed then all RTP_PLAYER_WORKAROUND
|
||||
block can be removed. This workaround use global number of streams (aka stream ID)
|
||||
to be used as port number in RTP Player to separate streams.
|
||||
*/
|
||||
#define RTP_PLAYER_WORKAROUND TRUE
|
||||
|
||||
#if RTP_PLAYER_WORKAROUND == TRUE
|
||||
wmem_tree_t *file_scope_stream_number = NULL;
|
||||
#endif
|
||||
/* ========================================================== */
|
||||
|
||||
static int proto_btavdtp = -1;
|
||||
|
||||
static int hf_btavdtp_data = -1;
|
||||
|
@ -239,18 +267,15 @@ static expert_field ei_btavdtp_sbc_min_bitpool_out_of_range = EI_INIT;
|
|||
static expert_field ei_btavdtp_sbc_max_bitpool_out_of_range = EI_INIT;
|
||||
static expert_field ei_btavdtp_unexpected_losc_data = EI_INIT;
|
||||
|
||||
static gboolean force_avdtp = FALSE;
|
||||
|
||||
static dissector_handle_t btavdtp_handle;
|
||||
static dissector_handle_t bta2dp_handle;
|
||||
static dissector_handle_t btvdp_handle;
|
||||
static dissector_handle_t rtp_handle;
|
||||
|
||||
|
||||
static wmem_tree_t *sep_list = NULL;
|
||||
static wmem_tree_t *sep_open = NULL;
|
||||
static wmem_tree_t *cid_to_type_table = NULL;
|
||||
static wmem_tree_t *media_packet_times = NULL;
|
||||
static wmem_tree_t *channels = NULL;
|
||||
static wmem_tree_t *sep_list = NULL;
|
||||
static wmem_tree_t *sep_open = NULL;
|
||||
static wmem_tree_t *media_packet_times = NULL;
|
||||
|
||||
/* A2DP declarations */
|
||||
static gint proto_bta2dp = -1;
|
||||
|
@ -262,6 +287,7 @@ static int hf_bta2dp_acp_seid = -1;
|
|||
static int hf_bta2dp_int_seid = -1;
|
||||
static int hf_bta2dp_codec = -1;
|
||||
static int hf_bta2dp_content_protection = -1;
|
||||
static int hf_bta2dp_stream_number = -1;
|
||||
static int hf_bta2dp_l_bit = -1;
|
||||
static int hf_bta2dp_cp_bit = -1;
|
||||
static int hf_bta2dp_reserved = -1;
|
||||
|
@ -461,24 +487,32 @@ typedef struct _sep_entry_t {
|
|||
enum sep_state state;
|
||||
} sep_entry_t;
|
||||
|
||||
typedef struct _cid_type_data_t {
|
||||
guint32 interface_id;
|
||||
guint32 adapter_id;
|
||||
guint32 chandle;
|
||||
guint32 type;
|
||||
guint16 cid;
|
||||
sep_entry_t *sep;
|
||||
} cid_type_data_t;
|
||||
|
||||
typedef struct _sep_data_t {
|
||||
gint codec;
|
||||
guint8 acp_seid;
|
||||
guint8 int_seid;
|
||||
gint content_protection_type;
|
||||
guint32 stream_number;
|
||||
media_packet_info_t *previous_media_packet_info;
|
||||
media_packet_info_t *current_media_packet_info;
|
||||
} sep_data_t;
|
||||
|
||||
typedef struct _media_stream_number_value_t {
|
||||
guint32 stream_number;
|
||||
} media_stream_number_value_t;
|
||||
|
||||
typedef struct _channels_info_t {
|
||||
gint32 control_scid;
|
||||
gint32 control_dcid;
|
||||
gint32 media_scid;
|
||||
gint32 media_dcid;
|
||||
gboolean media_is_local_psm;
|
||||
wmem_tree_t *stream_numbers;
|
||||
guint32 disconnect_in_frame;
|
||||
sep_entry_t *sep;
|
||||
} channels_info_t;
|
||||
|
||||
|
||||
void proto_register_btavdtp(void);
|
||||
void proto_reg_handoff_btavdtp(void);
|
||||
void proto_register_bta2dp(void);
|
||||
|
@ -488,6 +522,7 @@ void proto_register_btvdp(void);
|
|||
void proto_reg_handoff_btvdp(void);
|
||||
void proto_register_btvdp_content_protection_header_scms_t(void);
|
||||
|
||||
|
||||
static const char *
|
||||
get_sep_type(guint32 interface_id,
|
||||
guint32 adapter_id, guint32 chandle, guint32 direction, guint32 seid, guint32 frame_number)
|
||||
|
@ -827,7 +862,7 @@ dissect_capabilities(tvbuff_t *tvb, packet_info *pinfo,
|
|||
case SERVICE_CATEGORY_MEDIA_TRANSPORT:
|
||||
case SERVICE_CATEGORY_REPORTING:
|
||||
case SERVICE_CATEGORY_DELAY_REPORTING:
|
||||
/* losc should be 0*/
|
||||
/* losc should be 0 */
|
||||
break;
|
||||
case SERVICE_CATEGORY_RECOVERY:
|
||||
recovery_type = tvb_get_guint8(tvb, offset);
|
||||
|
@ -979,7 +1014,6 @@ dissect_capabilities(tvbuff_t *tvb, packet_info *pinfo,
|
|||
return offset;
|
||||
}
|
||||
|
||||
|
||||
static gint
|
||||
dissect_seid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset,
|
||||
gint seid_side, gint i_item, guint32 *sep_seid,
|
||||
|
@ -1047,14 +1081,14 @@ dissect_btavdtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
|||
guint delay;
|
||||
wmem_tree_t *subtree;
|
||||
wmem_tree_key_t key[8];
|
||||
channels_info_t *channels_info;
|
||||
guint32 interface_id;
|
||||
guint32 adapter_id;
|
||||
guint32 chandle;
|
||||
guint32 psm;
|
||||
guint32 direction;
|
||||
guint32 type;
|
||||
guint32 cid;
|
||||
guint32 frame_number;
|
||||
cid_type_data_t *cid_type_data;
|
||||
sep_entry_t *sep;
|
||||
tvbuff_t *next_tvb;
|
||||
guint32 seid;
|
||||
|
@ -1082,234 +1116,186 @@ dissect_btavdtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
|||
l2cap_data = (btl2cap_data_t *) data;
|
||||
DISSECTOR_ASSERT(l2cap_data);
|
||||
|
||||
if (!force_avdtp && !pinfo->fd->flags.visited && (l2cap_data->first_scid_frame == pinfo->fd->num ||
|
||||
l2cap_data->first_dcid_frame == pinfo->fd->num)) {
|
||||
cid_type_data = wmem_new(wmem_file_scope(), cid_type_data_t);
|
||||
cid_type_data->interface_id = l2cap_data->interface_id;
|
||||
cid_type_data->adapter_id = l2cap_data->adapter_id;
|
||||
cid_type_data->chandle = l2cap_data->chandle;
|
||||
cid_type_data->type = STREAM_TYPE_MEDIA;
|
||||
cid_type_data->cid = l2cap_data->cid;
|
||||
cid_type_data->sep = NULL;
|
||||
|
||||
/* heuristics for recognize signal AVDTP: first packet must be Discover Command */
|
||||
if ((tvb_get_guint8(tvb, offset) & 0x0F) == 0x00 &&
|
||||
tvb_get_guint8(tvb, offset + 1) == 0x01 &&
|
||||
tvb_length_remaining(tvb, offset) == HEADER_SIZE) {
|
||||
/* It is AVDTP Signaling cmd side */
|
||||
cid_type_data->type = STREAM_TYPE_SIGNAL;
|
||||
} else if ((tvb_get_guint8(tvb, offset) & 0x0F) == 0x02 &&
|
||||
tvb_get_guint8(tvb, offset + 1) == 0x01 &&
|
||||
tvb_length_remaining(tvb, offset) <= SEP_MAX * SEP_SIZE + HEADER_SIZE &&
|
||||
!(tvb_length_remaining(tvb, offset) % SEP_SIZE)) {
|
||||
/* It is AVDTP Signaling rsp side */
|
||||
cid_type_data->type = STREAM_TYPE_SIGNAL;
|
||||
} else {
|
||||
interface_id = cid_type_data->interface_id;
|
||||
adapter_id = cid_type_data->adapter_id;
|
||||
chandle = cid_type_data->chandle;
|
||||
frame_number = pinfo->fd->num;
|
||||
|
||||
key[0].length = 1;
|
||||
key[0].key = &interface_id;
|
||||
key[1].length = 1;
|
||||
key[1].key = &adapter_id;
|
||||
key[2].length = 1;
|
||||
key[2].key = &chandle;
|
||||
key[3].length = 0;
|
||||
key[3].key = NULL;
|
||||
|
||||
subtree = (wmem_tree_t *) wmem_tree_lookup32_array(sep_open, key);
|
||||
sep = (subtree) ? (sep_entry_t *) wmem_tree_lookup32_le(subtree, frame_number) : NULL;
|
||||
if (sep && sep->state == SEP_STATE_OPEN) {
|
||||
sep->state = SEP_STATE_IN_USE;
|
||||
cid_type_data->sep = sep;
|
||||
}
|
||||
}
|
||||
|
||||
interface_id = cid_type_data->interface_id;
|
||||
adapter_id = cid_type_data->adapter_id;
|
||||
chandle = cid_type_data->chandle;
|
||||
type = cid_type_data->type;
|
||||
cid = cid_type_data->cid;
|
||||
frame_number = pinfo->fd->num;
|
||||
|
||||
key[0].length = 1;
|
||||
key[0].key = &interface_id;
|
||||
key[1].length = 1;
|
||||
key[1].key = &adapter_id;
|
||||
key[2].length = 1;
|
||||
key[2].key = &chandle;
|
||||
key[3].length = 1;
|
||||
key[3].key = &cid;
|
||||
key[4].length = 1;
|
||||
key[4].key = &direction;
|
||||
key[5].length = 1;
|
||||
key[5].key = &type;
|
||||
key[6].length = 1;
|
||||
key[6].key = &frame_number;
|
||||
key[7].length = 0;
|
||||
key[7].key = NULL;
|
||||
|
||||
wmem_tree_insert32_array(cid_to_type_table, key, cid_type_data);
|
||||
}
|
||||
|
||||
interface_id = l2cap_data->interface_id;
|
||||
adapter_id = l2cap_data->adapter_id;
|
||||
chandle = l2cap_data->chandle;
|
||||
psm = l2cap_data->psm;
|
||||
cid = l2cap_data->cid;
|
||||
frame_number = pinfo->fd->num;
|
||||
|
||||
if (!force_avdtp) {
|
||||
key[0].length = 1;
|
||||
key[0].key = &interface_id;
|
||||
key[1].length = 1;
|
||||
key[1].key = &adapter_id;
|
||||
key[2].length = 1;
|
||||
key[2].key = &chandle;
|
||||
key[3].length = 1;
|
||||
key[3].key = &cid;
|
||||
key[4].length = 1;
|
||||
key[4].key = &direction;
|
||||
key[5].length = 0;
|
||||
key[5].key = NULL;
|
||||
subtree = (wmem_tree_t *) wmem_tree_lookup32_array(cid_to_type_table, key);
|
||||
if (subtree) {
|
||||
wmem_tree_t *type_tree;
|
||||
key[0].length = 1;
|
||||
key[0].key = &interface_id;
|
||||
key[1].length = 1;
|
||||
key[1].key = &adapter_id;
|
||||
key[2].length = 1;
|
||||
key[2].key = &chandle;
|
||||
key[3].length = 1;
|
||||
key[3].key = &psm;
|
||||
key[4].length = 0;
|
||||
key[4].key = NULL;
|
||||
|
||||
type_tree = (wmem_tree_t *) wmem_tree_lookup32(subtree, STREAM_TYPE_MEDIA);
|
||||
if (!type_tree)
|
||||
type_tree = (wmem_tree_t *) wmem_tree_lookup32(subtree, STREAM_TYPE_SIGNAL);
|
||||
subtree = type_tree;
|
||||
subtree = (wmem_tree_t *) wmem_tree_lookup32_array(channels, key);
|
||||
channels_info = (subtree) ? (channels_info_t *) wmem_tree_lookup32_le(subtree, frame_number) : NULL;
|
||||
if (!(channels_info && channels_info->disconnect_in_frame >= pinfo->fd->num)) {
|
||||
|
||||
channels_info = (channels_info_t *) wmem_new (wmem_file_scope(), channels_info_t);
|
||||
channels_info->control_scid = l2cap_data->scid;
|
||||
channels_info->control_dcid = l2cap_data->dcid;
|
||||
channels_info->media_scid = -1;
|
||||
channels_info->media_dcid = -1;
|
||||
channels_info->disconnect_in_frame = G_MAXUINT32;
|
||||
channels_info->sep = NULL;
|
||||
|
||||
if (!pinfo->fd->flags.visited) {
|
||||
key[4].length = 1;
|
||||
key[4].key = &frame_number;
|
||||
key[5].length = 0;
|
||||
key[5].key = NULL;
|
||||
|
||||
channels_info->stream_numbers = wmem_tree_new(wmem_file_scope());
|
||||
wmem_tree_insert32_array(channels, key, channels_info);
|
||||
} else {
|
||||
channels_info->stream_numbers = NULL;
|
||||
}
|
||||
cid_type_data = (subtree) ? (cid_type_data_t *) wmem_tree_lookup32_le(subtree, frame_number) : NULL;
|
||||
if (cid_type_data && cid_type_data->type == STREAM_TYPE_MEDIA) {
|
||||
/* AVDTP Media */
|
||||
}
|
||||
|
||||
if (!cid_type_data->sep) {
|
||||
if (!(l2cap_data->scid == channels_info->control_scid &&
|
||||
l2cap_data->dcid == channels_info->control_dcid) &&
|
||||
(channels_info->media_scid == -1 ||
|
||||
(l2cap_data->scid == channels_info->media_scid &&
|
||||
l2cap_data->dcid == channels_info->media_dcid))) {
|
||||
|
||||
if (!pinfo->fd->flags.visited && channels_info->media_scid == -1) {
|
||||
channels_info->media_scid = l2cap_data->scid;
|
||||
channels_info->media_dcid = l2cap_data->dcid;
|
||||
channels_info->media_is_local_psm = l2cap_data->is_local_psm;
|
||||
}
|
||||
/* Media Channel */
|
||||
|
||||
if (!channels_info->sep) {
|
||||
ti = proto_tree_add_item(tree, proto_btavdtp, tvb, offset, -1, ENC_NA);
|
||||
btavdtp_tree = proto_item_add_subtree(ti, ett_btavdtp);
|
||||
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, "Media stream on cid=0x%04x", l2cap_data->cid);
|
||||
proto_tree_add_item(btavdtp_tree, hf_btavdtp_data, tvb, offset, -1, ENC_NA);
|
||||
} else {
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, "Media stream ACP SEID [%u - %s %s]",
|
||||
channels_info->sep->seid, get_sep_media_type(
|
||||
interface_id, adapter_id, chandle, direction,
|
||||
channels_info->sep->seid,
|
||||
frame_number),
|
||||
get_sep_type(interface_id, adapter_id, chandle, direction,
|
||||
channels_info->sep->seid,
|
||||
frame_number));
|
||||
|
||||
if (channels_info->sep->media_type == MEDIA_TYPE_AUDIO) {
|
||||
sep_data_t sep_data;
|
||||
media_stream_number_value_t *media_stream_number_value;
|
||||
media_packet_info_t *previous_media_packet_info;
|
||||
media_packet_info_t *current_media_packet_info;
|
||||
nstime_t first_abs_ts;
|
||||
gdouble cummulative_frame_duration;
|
||||
|
||||
sep_data.codec = channels_info->sep->codec;
|
||||
sep_data.acp_seid = channels_info->sep->seid;
|
||||
sep_data.int_seid = channels_info->sep->int_seid;
|
||||
sep_data.content_protection_type = channels_info->sep->content_protection_type;
|
||||
|
||||
media_stream_number_value = (media_stream_number_value_t *) wmem_tree_lookup32_le(channels_info->stream_numbers, frame_number - 1);
|
||||
if (media_stream_number_value) {
|
||||
sep_data.stream_number = media_stream_number_value->stream_number;
|
||||
} else {
|
||||
sep_data.stream_number = 1;
|
||||
}
|
||||
|
||||
key[0].length = 1;
|
||||
key[0].key = &interface_id;
|
||||
key[1].length = 1;
|
||||
key[1].key = &adapter_id;
|
||||
key[2].length = 1;
|
||||
key[2].key = &chandle;
|
||||
key[3].length = 1;
|
||||
key[3].key = &cid;
|
||||
key[4].length = 1;
|
||||
key[4].key = &direction;
|
||||
key[5].length = 0;
|
||||
key[5].key = NULL;
|
||||
|
||||
subtree = (wmem_tree_t *) wmem_tree_lookup32_array(media_packet_times, key);
|
||||
previous_media_packet_info = (subtree) ? (media_packet_info_t *) wmem_tree_lookup32_le(subtree, frame_number - 1) : NULL;
|
||||
if (previous_media_packet_info && previous_media_packet_info->stream_number == sep_data.stream_number ) {
|
||||
sep_data.previous_media_packet_info = previous_media_packet_info;
|
||||
first_abs_ts = previous_media_packet_info->first_abs_ts;
|
||||
cummulative_frame_duration = previous_media_packet_info->cummulative_frame_duration;
|
||||
} else {
|
||||
first_abs_ts = pinfo->fd->abs_ts;
|
||||
cummulative_frame_duration = 0.0;
|
||||
sep_data.previous_media_packet_info = (media_packet_info_t *) wmem_new(wmem_epan_scope(), media_packet_info_t);
|
||||
sep_data.previous_media_packet_info->abs_ts = pinfo->fd->abs_ts;
|
||||
sep_data.previous_media_packet_info->first_abs_ts = first_abs_ts;
|
||||
sep_data.previous_media_packet_info->cummulative_frame_duration = cummulative_frame_duration;
|
||||
sep_data.previous_media_packet_info->stream_number = sep_data.stream_number;
|
||||
}
|
||||
|
||||
if (!pinfo->fd->flags.visited) {
|
||||
key[5].length = 1;
|
||||
key[5].key = &frame_number;
|
||||
key[6].length = 0;
|
||||
key[6].key = NULL;
|
||||
|
||||
current_media_packet_info = wmem_new(wmem_file_scope(), media_packet_info_t);
|
||||
current_media_packet_info->abs_ts = pinfo->fd->abs_ts;
|
||||
current_media_packet_info->first_abs_ts = first_abs_ts;
|
||||
current_media_packet_info->cummulative_frame_duration = cummulative_frame_duration;
|
||||
current_media_packet_info->stream_number = sep_data.stream_number;
|
||||
|
||||
wmem_tree_insert32_array(media_packet_times, key, current_media_packet_info);
|
||||
}
|
||||
|
||||
key[5].length = 0;
|
||||
key[5].key = NULL;
|
||||
|
||||
subtree = (wmem_tree_t *) wmem_tree_lookup32_array(media_packet_times, key);
|
||||
current_media_packet_info = (subtree) ? (media_packet_info_t *) wmem_tree_lookup32(subtree, frame_number) : NULL;
|
||||
if (current_media_packet_info)
|
||||
sep_data.current_media_packet_info = current_media_packet_info;
|
||||
else
|
||||
sep_data.current_media_packet_info = NULL;
|
||||
|
||||
next_tvb = tvb_new_subset_remaining(tvb, offset);
|
||||
call_dissector_with_data(bta2dp_handle, next_tvb, pinfo, tree, &sep_data);
|
||||
} else if (channels_info->sep->media_type == MEDIA_TYPE_VIDEO) {
|
||||
sep_data_t sep_data;
|
||||
|
||||
sep_data.codec = channels_info->sep->codec;
|
||||
sep_data.acp_seid = channels_info->sep->seid;
|
||||
sep_data.int_seid = channels_info->sep->int_seid;
|
||||
sep_data.content_protection_type = channels_info->sep->content_protection_type;
|
||||
|
||||
next_tvb = tvb_new_subset_remaining(tvb, offset);
|
||||
call_dissector_with_data(btvdp_handle, next_tvb, pinfo, tree, &sep_data);
|
||||
} else {
|
||||
ti = proto_tree_add_item(tree, proto_btavdtp, tvb, offset, -1, ENC_NA);
|
||||
btavdtp_tree = proto_item_add_subtree(ti, ett_btavdtp);
|
||||
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, "Media stream on cid=0x%04x", l2cap_data->cid);
|
||||
proto_tree_add_item(btavdtp_tree, hf_btavdtp_data, tvb, offset, -1, ENC_NA);
|
||||
} else {
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, "Media stream ACP SEID [%u - %s %s]",
|
||||
cid_type_data->sep->seid, get_sep_media_type(
|
||||
cid_type_data->interface_id,
|
||||
cid_type_data->adapter_id,
|
||||
cid_type_data->chandle,
|
||||
direction,
|
||||
cid_type_data->sep->seid,
|
||||
pinfo->fd->num),
|
||||
get_sep_type(cid_type_data->interface_id,
|
||||
cid_type_data->adapter_id,
|
||||
cid_type_data->chandle,
|
||||
direction,
|
||||
cid_type_data->sep->seid,
|
||||
pinfo->fd->num));
|
||||
|
||||
if (cid_type_data->sep->media_type == MEDIA_TYPE_AUDIO) {
|
||||
sep_data_t sep_data;
|
||||
media_packet_info_t *previous_media_packet_info;
|
||||
media_packet_info_t *current_media_packet_info;
|
||||
nstime_t first_abs_ts;
|
||||
gdouble cummulative_frame_duration;
|
||||
|
||||
sep_data.codec = cid_type_data->sep->codec;
|
||||
sep_data.acp_seid = cid_type_data->sep->seid;
|
||||
sep_data.int_seid = cid_type_data->sep->int_seid;
|
||||
sep_data.content_protection_type = cid_type_data->sep->content_protection_type;
|
||||
|
||||
interface_id = cid_type_data->interface_id;
|
||||
adapter_id = cid_type_data->adapter_id;
|
||||
chandle = cid_type_data->chandle;
|
||||
cid = cid_type_data->cid;
|
||||
frame_number = pinfo->fd->num;
|
||||
|
||||
key[0].length = 1;
|
||||
key[0].key = &interface_id;
|
||||
key[1].length = 1;
|
||||
key[1].key = &adapter_id;
|
||||
key[2].length = 1;
|
||||
key[2].key = &chandle;
|
||||
key[3].length = 1;
|
||||
key[3].key = &cid;
|
||||
key[4].length = 1;
|
||||
key[4].key = &direction;
|
||||
key[5].length = 0;
|
||||
key[5].key = NULL;
|
||||
subtree = (wmem_tree_t *) wmem_tree_lookup32_array(media_packet_times, key);
|
||||
|
||||
previous_media_packet_info = (subtree) ? (media_packet_info_t *) wmem_tree_lookup32_le(subtree, frame_number - 1) : NULL;
|
||||
if (previous_media_packet_info) {
|
||||
sep_data.previous_media_packet_info = previous_media_packet_info;
|
||||
first_abs_ts = previous_media_packet_info->first_abs_ts;
|
||||
cummulative_frame_duration = previous_media_packet_info->cummulative_frame_duration;
|
||||
} else {
|
||||
first_abs_ts = pinfo->fd->abs_ts;
|
||||
cummulative_frame_duration = 0.0;
|
||||
sep_data.previous_media_packet_info = (media_packet_info_t *) wmem_new(wmem_epan_scope(), media_packet_info_t);
|
||||
sep_data.previous_media_packet_info->abs_ts = pinfo->fd->abs_ts;
|
||||
sep_data.previous_media_packet_info->first_abs_ts = first_abs_ts;
|
||||
sep_data.previous_media_packet_info->cummulative_frame_duration = cummulative_frame_duration;
|
||||
}
|
||||
|
||||
if (!pinfo->fd->flags.visited) {
|
||||
key[5].length = 1;
|
||||
key[5].key = &frame_number;
|
||||
key[6].length = 0;
|
||||
key[6].key = NULL;
|
||||
|
||||
current_media_packet_info = wmem_new(wmem_file_scope(), media_packet_info_t);
|
||||
current_media_packet_info->abs_ts = pinfo->fd->abs_ts;
|
||||
current_media_packet_info->first_abs_ts = first_abs_ts;
|
||||
current_media_packet_info->cummulative_frame_duration = cummulative_frame_duration;
|
||||
|
||||
wmem_tree_insert32_array(media_packet_times, key, current_media_packet_info);
|
||||
}
|
||||
|
||||
key[5].length = 0;
|
||||
key[5].key = NULL;
|
||||
subtree = (wmem_tree_t *) wmem_tree_lookup32_array(media_packet_times, key);
|
||||
current_media_packet_info = (subtree) ? (media_packet_info_t *) wmem_tree_lookup32(subtree, frame_number) : NULL;
|
||||
if (current_media_packet_info)
|
||||
sep_data.current_media_packet_info = current_media_packet_info;
|
||||
else
|
||||
sep_data.current_media_packet_info = NULL;
|
||||
|
||||
next_tvb = tvb_new_subset_remaining(tvb, offset);
|
||||
call_dissector_with_data(bta2dp_handle, next_tvb, pinfo, tree, &sep_data);
|
||||
} else if (cid_type_data->sep->media_type == MEDIA_TYPE_VIDEO) {
|
||||
sep_data_t sep_data;
|
||||
|
||||
sep_data.codec = cid_type_data->sep->codec;
|
||||
sep_data.acp_seid = cid_type_data->sep->seid;
|
||||
sep_data.int_seid = cid_type_data->sep->int_seid;
|
||||
sep_data.content_protection_type = cid_type_data->sep->content_protection_type;
|
||||
|
||||
next_tvb = tvb_new_subset_remaining(tvb, offset);
|
||||
call_dissector_with_data(btvdp_handle, next_tvb, pinfo, tree, &sep_data);
|
||||
} else {
|
||||
ti = proto_tree_add_item(tree, proto_btavdtp, tvb, offset, -1, ENC_NA);
|
||||
btavdtp_tree = proto_item_add_subtree(ti, ett_btavdtp);
|
||||
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, "Media stream on cid=0x%04x", l2cap_data->cid);
|
||||
proto_tree_add_item(btavdtp_tree, hf_btavdtp_data, tvb, offset, -1, ENC_NA);
|
||||
}
|
||||
}
|
||||
|
||||
return tvb_length(tvb);
|
||||
} else if (!(cid_type_data && cid_type_data->type == STREAM_TYPE_SIGNAL)) {
|
||||
/* AVDTP not signaling - Unknown Media stream */
|
||||
ti = proto_tree_add_item(tree, proto_btavdtp, tvb, offset, -1, ENC_NA);
|
||||
btavdtp_tree = proto_item_add_subtree(ti, ett_btavdtp);
|
||||
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown stream on cid=0x%04x", l2cap_data->cid);
|
||||
proto_tree_add_item(btavdtp_tree, hf_btavdtp_data, tvb, offset, -1, ENC_NA);
|
||||
return tvb_length(tvb);
|
||||
}
|
||||
|
||||
return tvb_length(tvb);
|
||||
} else if (!(l2cap_data->scid == channels_info->control_scid &&
|
||||
l2cap_data->dcid == channels_info->control_dcid)) {
|
||||
/* Unknown Stream Channel */
|
||||
ti = proto_tree_add_item(tree, proto_btavdtp, tvb, offset, -1, ENC_NA);
|
||||
btavdtp_tree = proto_item_add_subtree(ti, ett_btavdtp);
|
||||
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown channel stream on cid=0x%04x", l2cap_data->cid);
|
||||
proto_tree_add_item(btavdtp_tree, hf_btavdtp_data, tvb, offset, -1, ENC_NA);
|
||||
return tvb_length(tvb);
|
||||
}
|
||||
|
||||
/* Signaling Channel */
|
||||
ti = proto_tree_add_item(tree, proto_btavdtp, tvb, offset, -1, ENC_NA);
|
||||
btavdtp_tree = proto_item_add_subtree(ti, ett_btavdtp);
|
||||
|
||||
|
@ -1508,6 +1494,24 @@ dissect_btavdtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
|||
offset += 1;
|
||||
break;
|
||||
}
|
||||
if (message_type == MESSAGE_TYPE_ACCEPT && !pinfo->fd->flags.visited) {
|
||||
|
||||
key[0].length = 1;
|
||||
key[0].key = &interface_id;
|
||||
key[1].length = 1;
|
||||
key[1].key = &adapter_id;
|
||||
key[2].length = 1;
|
||||
key[2].key = &chandle;
|
||||
key[3].length = 0;
|
||||
key[3].key = NULL;
|
||||
|
||||
subtree = (wmem_tree_t *) wmem_tree_lookup32_array(sep_open, key);
|
||||
sep = (subtree) ? (sep_entry_t *) wmem_tree_lookup32_le(subtree, frame_number) : NULL;
|
||||
if (sep && sep->state == SEP_STATE_OPEN) {
|
||||
sep->state = SEP_STATE_IN_USE;
|
||||
channels_info->sep = sep;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SIGNAL_ID_START:
|
||||
if (message_type == MESSAGE_TYPE_COMMAND) {
|
||||
|
@ -1528,6 +1532,42 @@ dissect_btavdtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
|||
offset += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (message_type == MESSAGE_TYPE_ACCEPT && !pinfo->fd->flags.visited) {
|
||||
media_stream_number_value_t *media_stream_number_value;
|
||||
guint32 stream_number = 0;
|
||||
|
||||
media_stream_number_value = (media_stream_number_value_t *) wmem_tree_lookup32_le(channels_info->stream_numbers, frame_number - 1);
|
||||
#if RTP_PLAYER_WORKAROUND == TRUE
|
||||
{
|
||||
media_stream_number_value_t *file_scope_stream_number_value;
|
||||
|
||||
if (media_stream_number_value) {
|
||||
stream_number = media_stream_number_value->stream_number;
|
||||
} else {
|
||||
file_scope_stream_number_value = (media_stream_number_value_t *) wmem_tree_lookup32_le(file_scope_stream_number, frame_number - 1);
|
||||
if (file_scope_stream_number_value)
|
||||
stream_number = file_scope_stream_number_value->stream_number + 1;
|
||||
else
|
||||
stream_number = 0;
|
||||
}
|
||||
|
||||
file_scope_stream_number_value = wmem_new(wmem_file_scope(), media_stream_number_value_t);
|
||||
file_scope_stream_number_value->stream_number = stream_number;
|
||||
wmem_tree_insert32(file_scope_stream_number, frame_number, file_scope_stream_number_value);
|
||||
}
|
||||
#else
|
||||
if (media_stream_number_value)
|
||||
stream_number = media_stream_number_value->stream_number;
|
||||
else
|
||||
stream_number = 0;
|
||||
#endif
|
||||
|
||||
media_stream_number_value = wmem_new(wmem_file_scope(), media_stream_number_value_t);
|
||||
media_stream_number_value->stream_number = stream_number + 1;
|
||||
|
||||
wmem_tree_insert32(channels_info->stream_numbers, frame_number, media_stream_number_value);
|
||||
}
|
||||
break;
|
||||
case SIGNAL_ID_CLOSE:
|
||||
if (message_type == MESSAGE_TYPE_COMMAND) {
|
||||
|
@ -1541,6 +1581,10 @@ dissect_btavdtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
|||
offset += 1;
|
||||
break;
|
||||
}
|
||||
if (!pinfo->fd->flags.visited && message_type == MESSAGE_TYPE_ACCEPT &&
|
||||
channels_info->disconnect_in_frame == G_MAXUINT32) {
|
||||
channels_info->disconnect_in_frame = pinfo->fd->num;
|
||||
}
|
||||
break;
|
||||
case SIGNAL_ID_SUSPEND:
|
||||
if (message_type == MESSAGE_TYPE_COMMAND) {
|
||||
|
@ -1574,6 +1618,10 @@ dissect_btavdtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
|||
offset += 1;
|
||||
break;
|
||||
}
|
||||
if (!pinfo->fd->flags.visited && message_type == MESSAGE_TYPE_ACCEPT &&
|
||||
channels_info->disconnect_in_frame == G_MAXUINT32) {
|
||||
channels_info->disconnect_in_frame = pinfo->fd->num;
|
||||
}
|
||||
break;
|
||||
case SIGNAL_ID_SECURITY_CONTROL:
|
||||
if (message_type == MESSAGE_TYPE_COMMAND) {
|
||||
|
@ -2285,15 +2333,13 @@ proto_register_btavdtp(void)
|
|||
"Bluetooth Protocol AVDTP version: 1.3",
|
||||
"Version of protocol supported by this dissector.");
|
||||
|
||||
prefs_register_bool_preference(module, "avdtp.force",
|
||||
"Force decoding as AVDTP Signaling",
|
||||
"Force decoding as AVDTP Signaling",
|
||||
&force_avdtp);
|
||||
|
||||
sep_list = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
|
||||
sep_open = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
|
||||
cid_to_type_table = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope()); /* cid: type */
|
||||
media_packet_times = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
|
||||
channels = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
|
||||
sep_list = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
|
||||
sep_open = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
|
||||
media_packet_times = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
|
||||
#if RTP_PLAYER_WORKAROUND == TRUE
|
||||
file_scope_stream_number = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2324,6 +2370,7 @@ dissect_bta2dp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
|||
sep_data.int_seid = 0;
|
||||
sep_data.previous_media_packet_info = NULL;
|
||||
sep_data.current_media_packet_info = NULL;
|
||||
sep_data.stream_number = 1;
|
||||
|
||||
if (force_a2dp_scms_t || force_a2dp_codec != CODEC_DEFAULT) {
|
||||
if (force_a2dp_scms_t)
|
||||
|
@ -2382,6 +2429,9 @@ dissect_bta2dp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
|||
PROTO_ITEM_SET_GENERATED(pitem);
|
||||
}
|
||||
|
||||
pitem = proto_tree_add_uint(bta2dp_tree, hf_bta2dp_stream_number, tvb, 0, 0, sep_data.stream_number);
|
||||
PROTO_ITEM_SET_GENERATED(pitem);
|
||||
|
||||
switch (sep_data.codec) {
|
||||
case CODEC_SBC:
|
||||
codec_dissector = sbc_handle;
|
||||
|
@ -2402,8 +2452,16 @@ dissect_bta2dp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
|||
bta2dp_codec_info.previous_media_packet_info = sep_data.previous_media_packet_info;
|
||||
bta2dp_codec_info.current_media_packet_info = sep_data.current_media_packet_info;
|
||||
|
||||
bluetooth_add_address(pinfo, &pinfo->net_dst, "BT A2DP", pinfo->fd->num, FALSE, &bta2dp_codec_info);
|
||||
#if RTP_PLAYER_WORKAROUND == TRUE
|
||||
/* XXX: Workaround to get multiple RTP streams, because converation are too
|
||||
weak to recognize Bluetooth streams (key is: guint32 interface_id, guint32 adapter_id, guint32 chandle, guint32 cid, guint32 direction -> guint32 stream_number) */
|
||||
pinfo->srcport = sep_data.stream_number;
|
||||
pinfo->destport = sep_data.stream_number;
|
||||
#endif
|
||||
|
||||
bluetooth_add_address(pinfo, &pinfo->net_dst, sep_data.stream_number, "BT A2DP", pinfo->fd->num, FALSE, &bta2dp_codec_info);
|
||||
call_dissector(rtp_handle, tvb, pinfo, tree);
|
||||
|
||||
offset += tvb_length_remaining(tvb, offset);
|
||||
|
||||
return offset;
|
||||
|
@ -2435,6 +2493,11 @@ proto_register_bta2dp(void)
|
|||
FT_UINT16, BASE_HEX, VALS(content_protection_type_vals), 0x0000,
|
||||
NULL, HFILL }
|
||||
},
|
||||
{ &hf_bta2dp_stream_number,
|
||||
{ "Stream Number", "bta2dp.stream_number",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x00,
|
||||
NULL, HFILL }
|
||||
},
|
||||
};
|
||||
|
||||
static gint *ett[] = {
|
||||
|
@ -2567,7 +2630,7 @@ dissect_btvdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
|||
btvdp_codec_info.codec_dissector = codec_dissector;
|
||||
btvdp_codec_info.content_protection_type = sep_data.content_protection_type;
|
||||
|
||||
bluetooth_add_address(pinfo, &pinfo->net_dst, "BT VDP", pinfo->fd->num, TRUE, &btvdp_codec_info);
|
||||
bluetooth_add_address(pinfo, &pinfo->net_dst, 0, "BT VDP", pinfo->fd->num, TRUE, &btvdp_codec_info);
|
||||
call_dissector(rtp_handle, tvb, pinfo, tree);
|
||||
offset += tvb_length_remaining(tvb, offset);
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ typedef struct _media_packet_info_t {
|
|||
nstime_t abs_ts;
|
||||
nstime_t first_abs_ts;
|
||||
gdouble cummulative_frame_duration;
|
||||
guint32 stream_number;
|
||||
} media_packet_info_t;
|
||||
|
||||
typedef struct _bta2dp_codec_info_t {
|
||||
|
|
|
@ -176,8 +176,8 @@ typedef struct _psm_data_t {
|
|||
guint32 interface_id;
|
||||
guint32 adapter_id;
|
||||
guint32 chandle;
|
||||
guint32 scid;
|
||||
guint32 dcid;
|
||||
gint32 scid;
|
||||
gint32 dcid;
|
||||
guint32 first_scid_frame;
|
||||
guint32 first_dcid_frame;
|
||||
guint16 psm;
|
||||
|
@ -1708,6 +1708,8 @@ dissect_btl2cap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
|||
l2cap_data->adapter_id = (acl_data) ? acl_data->adapter_id : HCI_ADAPTER_DEFAULT;
|
||||
l2cap_data->chandle = (acl_data) ? acl_data->chandle : 0;
|
||||
l2cap_data->cid = cid;
|
||||
l2cap_data->scid = -1;
|
||||
l2cap_data->dcid = -1;
|
||||
l2cap_data->is_local_psm = FALSE;
|
||||
l2cap_data->psm = 0;
|
||||
l2cap_data->first_scid_frame = 0;
|
||||
|
@ -1880,6 +1882,8 @@ dissect_btl2cap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
|||
col_append_str(pinfo->cinfo, COL_INFO, "Connectionless reception channel");
|
||||
|
||||
psm = tvb_get_letohs(tvb, offset);
|
||||
l2cap_data->scid = psm_data->scid;
|
||||
l2cap_data->dcid = psm_data->dcid;
|
||||
l2cap_data->psm = psm;
|
||||
|
||||
if (p_get_proto_data(pinfo->pool, pinfo, proto_btl2cap, BTL2CAP_PSM_CONV ) == NULL) {
|
||||
|
@ -2006,6 +2010,8 @@ dissect_btl2cap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
|||
}
|
||||
|
||||
psm = psm_data->psm;
|
||||
l2cap_data->scid = psm_data->scid;
|
||||
l2cap_data->dcid = psm_data->dcid;
|
||||
l2cap_data->psm = psm;
|
||||
l2cap_data->is_local_psm = psm_data->local_service;
|
||||
l2cap_data->first_scid_frame = psm_data->first_scid_frame;
|
||||
|
|
|
@ -54,6 +54,8 @@ typedef struct _btl2cap_data_t {
|
|||
guint32 adapter_id;
|
||||
guint16 chandle; /* only low 12 bits used */
|
||||
guint16 cid;
|
||||
gint32 scid;
|
||||
gint32 dcid;
|
||||
gboolean is_local_psm; /* otherwise it is PSM in remote device */
|
||||
guint16 psm;
|
||||
guint32 first_scid_frame;
|
||||
|
|
|
@ -1131,7 +1131,7 @@ rtp_dyn_payload_free(rtp_dyn_payload_t *rtp_dyn_payload)
|
|||
}
|
||||
|
||||
void
|
||||
bluetooth_add_address(packet_info *pinfo, address *addr,
|
||||
bluetooth_add_address(packet_info *pinfo, address *addr, guint32 stream_number,
|
||||
const gchar *setup_method, guint32 setup_frame_number,
|
||||
gboolean is_video, void *data)
|
||||
{
|
||||
|
@ -1154,14 +1154,14 @@ bluetooth_add_address(packet_info *pinfo, address *addr,
|
|||
* 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_BLUETOOTH, 0, 0,
|
||||
p_conv = find_conversation(setup_frame_number, addr, &null_addr, PT_BLUETOOTH, stream_number, stream_number,
|
||||
NO_ADDR_B | NO_PORT_B);
|
||||
|
||||
/*
|
||||
* 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_BLUETOOTH, 0, 0,
|
||||
p_conv = conversation_new(setup_frame_number, addr, &null_addr, PT_BLUETOOTH, stream_number, stream_number,
|
||||
NO_ADDR2 | NO_PORT2);
|
||||
}
|
||||
|
||||
|
|
|
@ -210,6 +210,6 @@ void srtp_add_address(packet_info *pinfo,
|
|||
|
||||
/* Add an Bluetooth conversation with the given details */
|
||||
void
|
||||
bluetooth_add_address(packet_info *pinfo, address *addr,
|
||||
bluetooth_add_address(packet_info *pinfo, address *addr, guint32 stream_number,
|
||||
const gchar *setup_method, guint32 setup_frame_number,
|
||||
gboolean is_video, void *data);
|
||||
|
|
Loading…
Reference in New Issue