wireshark/epan/dissectors/packet-btavdtp.c

2503 lines
107 KiB
C

/* packet-btavdtp.c
* Routines for Bluetooth AVDTP dissection
*
* Copyright 2012, Michal Labedzki for Tieto Corporation
*
* $Id$
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <epan/packet.h>
#include <epan/expert.h>
#include <epan/prefs.h>
#include <epan/wmem/wmem.h>
#include "packet-btl2cap.h"
#include "packet-btsdp.h"
#include "packet-btavdtp.h"
#include "packet-rtp.h"
#define AVDTP_MESSAGE_TYPE_MASK 0x03
#define AVDTP_PACKET_TYPE_MASK 0x0C
#define AVDTP_TRANSACTION_MASK 0xF0
#define AVDTP_SIGNAL_ID_MASK 0x3F
#define AVDTP_RFA0_MASK 0xC0
#define MESSAGE_TYPE_COMMAND 0x00
#define MESSAGE_TYPE_GENERAL_REJECT 0x01
#define MESSAGE_TYPE_ACCEPT 0x02
#define MESSAGE_TYPE_REJECT 0x03
#define PACKET_TYPE_SINGLE 0x00
#define PACKET_TYPE_START 0x01
#define PACKET_TYPE_CONTINUE 0x02
#define PACKET_TYPE_END 0x03
#define SIGNAL_ID_DISCOVER 0x01
#define SIGNAL_ID_GET_CAPABILITIES 0x02
#define SIGNAL_ID_SET_CONFIGURATION 0x03
#define SIGNAL_ID_GET_CONFIGURATION 0x04
#define SIGNAL_ID_RECONFIGURE 0x05
#define SIGNAL_ID_OPEN 0x06
#define SIGNAL_ID_START 0x07
#define SIGNAL_ID_CLOSE 0x08
#define SIGNAL_ID_SUSPEND 0x09
#define SIGNAL_ID_ABORT 0x0A
#define SIGNAL_ID_SECURITY_CONTROL 0x0B
#define SIGNAL_ID_GET_ALL_CAPABILITIES 0x0C
#define SIGNAL_ID_DELAY_REPORT 0x0D
#define SERVICE_CATEGORY_MEDIA_TRANSPORT 0x01
#define SERVICE_CATEGORY_REPORTING 0x02
#define SERVICE_CATEGORY_RECOVERY 0x03
#define SERVICE_CATEGORY_CONTENT_PROTECTION 0x04
#define SERVICE_CATEGORY_HEADER_COMPRESSION 0x05
#define SERVICE_CATEGORY_MULTIPLEXING 0x06
#define SERVICE_CATEGORY_MEDIA_CODEC 0x07
#define SERVICE_CATEGORY_DELAY_REPORTING 0x08
#define MEDIA_TYPE_AUDIO 0x00
#define MEDIA_TYPE_VIDEO 0x01
#define SEID_ACP 0x00
#define SEID_INT 0x01
#define STREAM_TYPE_MEDIA 0x00
#define STREAM_TYPE_SIGNAL 0x01
#define CODEC_SBC 0x00
#define CODEC_MPEG12_AUDIO 0x01
#define CODEC_MPEG24_AAC 0x02
#define CODEC_ATRAC 0x04
#define CODEC_H263_BASELINE 0x01
#define CODEC_MPEG4_VSP 0x02
#define CODEC_H263_PROFILE_3 0x03
#define CODEC_H263_PROFILE_8 0x04
#define CODEC_VENDOR 0xFF
#define HEADER_SIZE 2
#define SEP_MAX 64
#define SEP_SIZE 2
static int proto_btavdtp = -1;
static int hf_btavdtp_data = -1;
static int hf_btavdtp_message_type = -1;
static int hf_btavdtp_packet_type = -1;
static int hf_btavdtp_transaction = -1;
static int hf_btavdtp_signal = -1;
static int hf_btavdtp_signal_id = -1;
static int hf_btavdtp_rfa0 = -1;
static int hf_btavdtp_number_of_signal_packets = -1;
static int hf_btavdtp_sep_seid = -1;
static int hf_btavdtp_sep_inuse = -1;
static int hf_btavdtp_sep_rfa0 = -1;
static int hf_btavdtp_sep_media_type = -1;
static int hf_btavdtp_sep_type = -1;
static int hf_btavdtp_sep_rfa1 = -1;
static int hf_btavdtp_error_code = -1;
static int hf_btavdtp_acp_sep = -1;
static int hf_btavdtp_acp_seid_item = -1;
static int hf_btavdtp_int_seid_item = -1;
static int hf_btavdtp_acp_seid = -1;
static int hf_btavdtp_int_seid = -1;
static int hf_btavdtp_service_category = -1;
static int hf_btavdtp_rfa_seid = -1;
static int hf_btavdtp_delay = -1;
static int hf_btavdtp_length_of_service_category = -1;
static int hf_btavdtp_recovery_type = -1;
static int hf_btavdtp_maximum_recovery_window_size = -1;
static int hf_btavdtp_maximum_number_of_media_packet_in_parity_code = -1;
static int hf_btavdtp_multiplexing_fragmentation = -1;
static int hf_btavdtp_multiplexing_rfa = -1;
static int hf_btavdtp_multiplexing_tsid = -1;
static int hf_btavdtp_multiplexing_tcid = -1;
static int hf_btavdtp_multiplexing_entry_rfa = -1;
static int hf_btavdtp_header_compression_backch = -1;
static int hf_btavdtp_header_compression_media = -1;
static int hf_btavdtp_header_compression_recovery = -1;
static int hf_btavdtp_header_compression_rfa = -1;
static int hf_btavdtp_content_protection_type = -1;
static int hf_btavdtp_media_codec_media_type = -1;
static int hf_btavdtp_media_codec_rfa = -1;
static int hf_btavdtp_media_codec_unknown_type = -1;
static int hf_btavdtp_media_codec_audio_type = -1;
static int hf_btavdtp_media_codec_video_type = -1;
static int hf_btavdtp_sbc_sampling_frequency_16000 = -1;
static int hf_btavdtp_sbc_sampling_frequency_32000 = -1;
static int hf_btavdtp_sbc_sampling_frequency_44100 = -1;
static int hf_btavdtp_sbc_sampling_frequency_48000 = -1;
static int hf_btavdtp_sbc_channel_mode_mono = -1;
static int hf_btavdtp_sbc_channel_mode_dual_channel = -1;
static int hf_btavdtp_sbc_channel_mode_stereo = -1;
static int hf_btavdtp_sbc_channel_mode_joint_stereo = -1;
static int hf_btavdtp_sbc_block_4 = -1;
static int hf_btavdtp_sbc_block_8 = -1;
static int hf_btavdtp_sbc_block_12 = -1;
static int hf_btavdtp_sbc_block_16 = -1;
static int hf_btavdtp_sbc_subbands_4 = -1;
static int hf_btavdtp_sbc_subbands_8 = -1;
static int hf_btavdtp_sbc_allocation_method_snr = -1;
static int hf_btavdtp_sbc_allocation_method_loudness = -1;
static int hf_btavdtp_sbc_min_bitpool = -1;
static int hf_btavdtp_sbc_max_bitpool = -1;
static int hf_btavdtp_mpeg12_layer_1 = -1;
static int hf_btavdtp_mpeg12_layer_2 = -1;
static int hf_btavdtp_mpeg12_layer_3 = -1;
static int hf_btavdtp_mpeg12_crc_protection = -1;
static int hf_btavdtp_mpeg12_channel_mode_mono = -1;
static int hf_btavdtp_mpeg12_channel_mode_dual_channel = -1;
static int hf_btavdtp_mpeg12_channel_mode_stereo = -1;
static int hf_btavdtp_mpeg12_channel_mode_joint_stereo = -1;
static int hf_btavdtp_mpeg12_rfa = -1;
static int hf_btavdtp_mpeg12_mpf_2 = -1;
static int hf_btavdtp_mpeg12_sampling_frequency_16000 = -1;
static int hf_btavdtp_mpeg12_sampling_frequency_22050 = -1;
static int hf_btavdtp_mpeg12_sampling_frequency_24000 = -1;
static int hf_btavdtp_mpeg12_sampling_frequency_32000 = -1;
static int hf_btavdtp_mpeg12_sampling_frequency_44100 = -1;
static int hf_btavdtp_mpeg12_sampling_frequency_48000 = -1;
static int hf_btavdtp_mpeg12_vbr_supported = -1;
static int hf_btavdtp_mpeg12_bit_rate = -1;
static int hf_btavdtp_mpeg24_object_type_mpeg2_aac_lc = -1;
static int hf_btavdtp_mpeg24_object_type_mpeg4_aac_lc = -1;
static int hf_btavdtp_mpeg24_object_type_mpeg4_aac_ltp = -1;
static int hf_btavdtp_mpeg24_object_type_mpeg4_aac_scalable = -1;
static int hf_btavdtp_mpeg24_object_type_rfa = -1;
static int hf_btavdtp_mpeg24_sampling_frequency_8000 = -1;
static int hf_btavdtp_mpeg24_sampling_frequency_11025 = -1;
static int hf_btavdtp_mpeg24_sampling_frequency_12000 = -1;
static int hf_btavdtp_mpeg24_sampling_frequency_16000 = -1;
static int hf_btavdtp_mpeg24_sampling_frequency_22050 = -1;
static int hf_btavdtp_mpeg24_sampling_frequency_24000 = -1;
static int hf_btavdtp_mpeg24_sampling_frequency_32000 = -1;
static int hf_btavdtp_mpeg24_sampling_frequency_44100 = -1;
static int hf_btavdtp_mpeg24_sampling_frequency_48000 = -1;
static int hf_btavdtp_mpeg24_sampling_frequency_64000 = -1;
static int hf_btavdtp_mpeg24_sampling_frequency_88200 = -1;
static int hf_btavdtp_mpeg24_sampling_frequency_96000 = -1;
static int hf_btavdtp_mpeg24_channels_1 = -1;
static int hf_btavdtp_mpeg24_channels_2 = -1;
static int hf_btavdtp_mpeg24_rfa = -1;
static int hf_btavdtp_mpeg24_vbr_supported = -1;
static int hf_btavdtp_mpeg24_bit_rate = -1;
static int hf_btavdtp_atrac_version = -1;
static int hf_btavdtp_atrac_channel_mode_single_channel = -1;
static int hf_btavdtp_atrac_channel_mode_dual_channel = -1;
static int hf_btavdtp_atrac_channel_mode_joint_stereo = -1;
static int hf_btavdtp_atrac_rfa1 = -1;
static int hf_btavdtp_atrac_rfa2 = -1;
static int hf_btavdtp_atrac_sampling_frequency_44100 = -1;
static int hf_btavdtp_atrac_sampling_frequency_48000 = -1;
static int hf_btavdtp_atrac_vbr_supported = -1;
static int hf_btavdtp_atrac_bit_rate = -1;
static int hf_btavdtp_atrac_maximum_sul = -1;
static int hf_btavdtp_atrac_rfa3 = -1;
static int hf_btavdtp_h263_level_10 = -1;
static int hf_btavdtp_h263_level_20 = -1;
static int hf_btavdtp_h263_level_30 = -1;
static int hf_btavdtp_h263_level_rfa = -1;
static int hf_btavdtp_mpeg4_level_0 = -1;
static int hf_btavdtp_mpeg4_level_1 = -1;
static int hf_btavdtp_mpeg4_level_2 = -1;
static int hf_btavdtp_mpeg4_level_3 = -1;
static int hf_btavdtp_mpeg4_level_rfa = -1;
static int hf_btavdtp_vendor_id = -1;
static int hf_btavdtp_vendor_specific_codec_id = -1;
static int hf_btavdtp_vendor_specific_value = -1;
static int hf_btavdtp_capabilities = -1;
static int hf_btavdtp_service = -1;
static int hf_btavdtp_service_multiplexing_entry = -1;
static gint ett_btavdtp = -1;
static gint ett_btavdtp_sep = -1;
static gint ett_btavdtp_capabilities = -1;
static gint ett_btavdtp_service = -1;
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;
/* A2DP declarations */
static gint proto_bta2dp = -1;
static gint ett_bta2dp = -1;
static gint proto_bta2dp_cph_scms_t = -1;
static gint ett_bta2dp_cph_scms_t = -1;
static int hf_bta2dp_codec = -1;
static int hf_bta2dp_content_protection = -1;
static int hf_bta2dp_l_bit = -1;
static int hf_bta2dp_cp_bit = -1;
static int hf_bta2dp_reserved = -1;
static dissector_handle_t sbc_handle;
static dissector_handle_t mp2t_handle;
static dissector_handle_t mpeg_audio_handle;
static dissector_handle_t atrac_handle;
static gboolean force_a2dp_scms_t = FALSE;
static gint force_a2dp_codec = CODEC_SBC;
static const enum_val_t pref_a2dp_codec[] = {
{ "sbc", "SBC", CODEC_SBC },
{ "mp2t", "MPEG12 AUDIO", CODEC_MPEG12_AUDIO },
{ "mpeg-audio", "MPEG24 AAC", CODEC_MPEG24_AAC },
/* XXX: Not supported in Wireshark yet { "atrac", "ATRAC", CODEC_ATRAC },*/
{ NULL, NULL, 0 }
};
/* VDP declarations */
static gint proto_btvdp = -1;
static gint ett_btvdp = -1;
static gint proto_btvdp_cph_scms_t = -1;
static gint ett_btvdp_cph_scms_t = -1;
static int hf_btvdp_codec = -1;
static int hf_btvdp_content_protection = -1;
static int hf_btvdp_l_bit = -1;
static int hf_btvdp_cp_bit = -1;
static int hf_btvdp_reserved = -1;
static dissector_handle_t h263_handle;
static dissector_handle_t mp4v_es_handle;
static gboolean force_vdp_scms_t = FALSE;
static gint force_vdp_codec = CODEC_H263_BASELINE;
static const enum_val_t pref_vdp_codec[] = {
{ "h263", "H263", CODEC_H263_BASELINE },
{ "mp4v-es", "MPEG4 VSP", CODEC_MPEG4_VSP },
{ NULL, NULL, 0 }
};
static const value_string message_type_vals[] = {
{ 0x00, "Command" },
{ 0x01, "GeneralReject" },
{ 0x02, "ResponseAccept" },
{ 0x03, "ResponseReject" },
{ 0, NULL }
};
static const value_string packet_type_vals[] = {
{ 0x00, "Single" },
{ 0x01, "Start" },
{ 0x02, "Continue" },
{ 0x03, "End" },
{ 0, NULL }
};
static const value_string signal_id_vals[] = {
{ 0x00, "Reserved" },
{ 0x01, "Discover" },
{ 0x02, "GetCapabilities" },
{ 0x03, "SetConfiguration" },
{ 0x04, "GetConfiguration" },
{ 0x05, "Reconfigure" },
{ 0x06, "Open" },
{ 0x07, "Start" },
{ 0x08, "Close" },
{ 0x09, "Suspend" },
{ 0x0A, "Abort" },
{ 0x0B, "SecurityControl" },
{ 0x0C, "GetAllCapabilities" },
{ 0x0D, "DelayReport" },
{ 0, NULL }
};
static const value_string media_type_vals[] = {
{ 0x00, "Audio" },
{ 0x01, "Video" },
{ 0x02, "Multimedia" },
{ 0, NULL }
};
static const value_string sep_type_vals[] = {
{ 0x00, "Source" },
{ 0x01, "Sink" },
{ 0, NULL }
};
static const value_string true_false[] = {
{ 0x00, "False" },
{ 0x01, "True" },
{ 0, NULL }
};
static const value_string error_code_vals[] = {
/* ACP to INT, Signal Response Header Error Codes */
{ 0x01, "Bad Header Format" },
/* ACP to INT, Signal Response Payload Format Error Codes */
{ 0x11, "Bad Length" },
{ 0x12, "Bad ACP SEID" },
{ 0x13, "SEP In Use" },
{ 0x14, "SEP Not In Use" },
{ 0x17, "Bad Service Category" },
{ 0x18, "Bad Payload Format" },
{ 0x19, "Not Supported Command" },
{ 0x1A, "Invalid Capabilities" },
/* ACP to INT, Signal Response Transport Service Capabilities Error Codes */
{ 0x22, "Bad Recovery Type" },
{ 0x23, "Bad Media Transport Format" },
{ 0x25, "Bad Recovery Format" },
{ 0x26, "Bad Header Compression Format" },
{ 0x27, "Bad Content Protection Format" },
{ 0x28, "Bad Multiplexing Format" },
{ 0x29, "Unsupported Configuration" },
/* ACP to INT, Procedure Error Codes */
{ 0x31, "Bad State" },
{ 0, NULL }
};
static const value_string service_category_vals[] = {
{ 0x01, "Media Transport" },
{ 0x02, "Reporting" },
{ 0x03, "Recovery" },
{ 0x04, "Content Protection" },
{ 0x05, "Header Compression" },
{ 0x06, "Multiplexing" },
{ 0x07, "Media Codec" },
{ 0x08, "Delay Reporting" },
{ 0, NULL }
};
static const value_string recovery_type_vals[] = {
{ 0x00, "Forbidden" },
{ 0x01, "RFC2733" },
{ 0, NULL }
};
static const value_string multiplexing_tsid_vals[] = {
{ 0x00, "Used for TSID query" },
{ 0x1F, "RFD" },
{ 0, NULL }
};
static const value_string multiplexing_tcid_vals[] = {
{ 0x00, "Used for TCID query" },
{ 0x1F, "RFD" },
{ 0, NULL }
};
static const value_string media_codec_audio_type_vals[] = {
{ 0x00, "SBC" },
{ 0x01, "MPEG-1,2 Audio" },
{ 0x02, "MPEG-2,4 AAC" },
{ 0x04, "ATRAC family" },
{ 0xFF, "non-A2DP" },
{ 0, NULL }
};
static const value_string media_codec_video_type_vals[] = {
{ 0x01, "H.263 baseline" },
{ 0x02, "MPEG-4 Visual Simple Profile" },
{ 0x03, "H.263 profile 3" },
{ 0x04, "H.263 profile 8" },
{ 0xFF, "non-VDP" },
{ 0, NULL }
};
static const value_string content_protection_type_vals[] = {
{ 0x01, "DTCP" },
{ 0x02, "SCMS-T" },
{ 0, NULL }
};
extern value_string_ext bthci_evt_comp_id_ext;
enum sep_state {
SEP_STATE_FREE,
SEP_STATE_OPEN,
SEP_STATE_IN_USE
};
typedef struct _sep_entry_t {
guint8 seid;
guint8 type;
guint8 media_type;
gint codec;
gint content_protection_type;
enum sep_state state;
} sep_entry_t;
typedef struct _cid_type_data_t {
guint32 type;
guint16 cid;
sep_entry_t *sep;
} cid_type_data_t;
typedef struct _sep_data_t {
gint codec;
gint content_protection_type;
} sep_data_t;
void proto_register_btavdtp(void);
void proto_reg_handoff_btavdtp(void);
void proto_register_bta2dp(void);
void proto_reg_handoff_bta2dp(void);
void proto_register_bta2dp_content_protection_header_scms_t(void);
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 frame_number, guint seid)
{
sep_entry_t *sep;
wmem_tree_key_t key[3];
guint32 t_seid;
guint32 t_frame_number;
t_seid = seid;
t_frame_number = frame_number;
key[0].length = 1;
key[0].key = &t_seid;
key[1].length = 1;
key[1].key = &t_frame_number;
key[2].length = 0;
key[2].key = NULL;
sep = (sep_entry_t *)wmem_tree_lookup32_array_le(sep_list, key);
if (sep && sep->seid == seid) {
return val_to_str_const(sep->type, sep_type_vals, "unknown");
}
return "unknown";
}
static const char *
get_sep_media_type(guint32 frame_number, guint seid)
{
sep_entry_t *sep;
wmem_tree_key_t key[3];
guint32 t_seid;
guint32 t_frame_number;
t_seid = seid;
t_frame_number = frame_number;
key[0].length = 1;
key[0].key = &t_seid;
key[1].length = 1;
key[1].key = &t_frame_number;
key[2].length = 0;
key[2].key = NULL;
sep = (sep_entry_t *)wmem_tree_lookup32_array_le(sep_list, key);
if (sep && sep->seid == seid) {
return val_to_str_const(sep->media_type, media_type_vals, "unknown");
}
return "unknown";
}
static gint
dissect_sep(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
{
proto_tree *sep_tree;
proto_item *sep_item;
guint i_sep = 1;
guint media_type;
guint type;
guint seid;
guint in_use;
guint items;
sep_entry_t *sep_data;
wmem_tree_key_t key[3];
guint32 t_seid;
guint32 t_frame_number;
items = tvb_length_remaining(tvb, offset) / 2;
while (tvb_length_remaining(tvb, offset) > 0) {
seid = tvb_get_guint8(tvb, offset);
in_use = seid & 0x02;
seid = seid >> 2;
media_type = tvb_get_guint8(tvb, offset + 1) >> 4;
type = (tvb_get_guint8(tvb, offset + 1) & 0x08) >> 3;
sep_item = proto_tree_add_none_format(tree, hf_btavdtp_acp_sep, tvb, offset, 2, "ACP SEP [%u - %s %s] item %u/%u",
seid, val_to_str_const(media_type, media_type_vals, "unknown"),
val_to_str_const(type, sep_type_vals, "unknown"), i_sep, items);
sep_tree = proto_item_add_subtree(sep_item, ett_btavdtp_sep);
proto_tree_add_item(sep_tree, hf_btavdtp_sep_seid , tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(sep_tree, hf_btavdtp_sep_inuse, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(sep_tree, hf_btavdtp_sep_rfa0 , tvb, offset, 1, ENC_BIG_ENDIAN);
offset+=1;
proto_tree_add_item(sep_tree, hf_btavdtp_sep_media_type, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(sep_tree, hf_btavdtp_sep_type , tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(sep_tree, hf_btavdtp_sep_rfa1 , tvb, offset, 1, ENC_BIG_ENDIAN);
/* save information for later recognizing */
t_seid = seid;
t_frame_number = pinfo->fd->num;
key[0].length = 1;
key[0].key = &t_seid;
key[1].length = 1;
key[1].key = &t_frame_number;
key[2].length = 0;
key[2].key = NULL;
if (!pinfo->fd->flags.visited) {
sep_data = wmem_new(wmem_file_scope(), sep_entry_t);
sep_data->seid = seid;
sep_data->type = type;
sep_data->codec = -1;
sep_data->content_protection_type = 0;
sep_data->media_type = media_type;
if (in_use) {
sep_data->state = SEP_STATE_IN_USE;
} else {
sep_data->state = SEP_STATE_FREE;
}
wmem_tree_insert32_array(sep_list, key, sep_data);
}
offset += 1;
i_sep += 1;
}
col_append_fstr(pinfo->cinfo, COL_INFO, " - items: %u", items);
return offset;
}
static gint
dissect_codec(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset,
guint losc, gint media_type, gint media_codec_type)
{
proto_item *pitem;
guint bitpool;
switch(media_type) {
case MEDIA_TYPE_AUDIO:
switch(media_codec_type) {
case CODEC_SBC:
proto_tree_add_item(tree, hf_btavdtp_sbc_sampling_frequency_16000, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_sbc_sampling_frequency_32000, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_sbc_sampling_frequency_44100, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_sbc_sampling_frequency_48000, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_sbc_channel_mode_mono, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_sbc_channel_mode_dual_channel, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_sbc_channel_mode_stereo, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_sbc_channel_mode_joint_stereo, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_sbc_block_4, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_sbc_block_8, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_sbc_block_12, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_sbc_block_16, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_sbc_subbands_4, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_sbc_subbands_8, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_sbc_allocation_method_snr, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_sbc_allocation_method_loudness, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
pitem = proto_tree_add_item(tree, hf_btavdtp_sbc_min_bitpool, tvb, offset + 2, 1, ENC_BIG_ENDIAN);
bitpool = tvb_get_guint8(tvb, offset + 2);
if (bitpool < 2 || bitpool > 250) {
expert_add_info(pinfo, pitem, &ei_btavdtp_sbc_min_bitpool_out_of_range);
}
pitem = proto_tree_add_item(tree, hf_btavdtp_sbc_max_bitpool, tvb, offset + 3, 1, ENC_BIG_ENDIAN);
bitpool = tvb_get_guint8(tvb, offset + 3);
if (bitpool < 2 || bitpool > 250) {
expert_add_info(pinfo, pitem, &ei_btavdtp_sbc_max_bitpool_out_of_range);
}
break;
case CODEC_MPEG12_AUDIO:
proto_tree_add_item(tree, hf_btavdtp_mpeg12_layer_1, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg12_layer_2, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg12_layer_3, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg12_crc_protection, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg12_channel_mode_mono, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg12_channel_mode_dual_channel, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg12_channel_mode_stereo, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg12_channel_mode_joint_stereo, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg12_rfa, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg12_mpf_2, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg12_sampling_frequency_16000, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg12_sampling_frequency_22050, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg12_sampling_frequency_24000, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg12_sampling_frequency_32000, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg12_sampling_frequency_44100, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg12_sampling_frequency_48000, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg12_vbr_supported, tvb, offset + 2, 2, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg12_bit_rate, tvb, offset + 2, 2, ENC_BIG_ENDIAN);
break;
case CODEC_MPEG24_AAC:
proto_tree_add_item(tree, hf_btavdtp_mpeg24_object_type_mpeg2_aac_lc, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg24_object_type_mpeg4_aac_lc, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg24_object_type_mpeg4_aac_ltp, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg24_object_type_mpeg4_aac_scalable, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg24_object_type_rfa, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg24_sampling_frequency_8000, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg24_sampling_frequency_11025, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg24_sampling_frequency_12000, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg24_sampling_frequency_16000, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg24_sampling_frequency_22050, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg24_sampling_frequency_24000, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg24_sampling_frequency_32000, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg24_sampling_frequency_44100, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg24_sampling_frequency_48000, tvb, offset + 2, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg24_sampling_frequency_64000, tvb, offset + 2, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg24_sampling_frequency_88200, tvb, offset + 2, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg24_sampling_frequency_96000, tvb, offset + 2, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg24_channels_1, tvb, offset + 2, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg24_channels_2, tvb, offset + 2, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg24_rfa, tvb, offset + 2, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg24_vbr_supported, tvb, offset + 3, 3, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg24_bit_rate, tvb, offset + 3, 3, ENC_BIG_ENDIAN);
break;
case CODEC_ATRAC:
proto_tree_add_item(tree, hf_btavdtp_atrac_version, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_atrac_channel_mode_single_channel, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_atrac_channel_mode_dual_channel, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_atrac_channel_mode_joint_stereo, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_atrac_rfa1, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_atrac_rfa2, tvb, offset + 1, 3, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_atrac_sampling_frequency_44100, tvb, offset + 1, 3, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_atrac_sampling_frequency_48000, tvb, offset + 1, 3, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_atrac_vbr_supported, tvb, offset + 3, 3, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_atrac_bit_rate, tvb, offset + 3, 3, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_atrac_maximum_sul, tvb, offset + 4, 2, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_atrac_rfa3, tvb, offset + 6, 1, ENC_BIG_ENDIAN);
break;
case CODEC_VENDOR: /* non-A2DP */
proto_tree_add_item(tree, hf_btavdtp_vendor_id, tvb, offset, 4, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_vendor_specific_codec_id, tvb, offset + 4, 2, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_vendor_specific_value, tvb, offset + 6, losc - 6, ENC_NA);
break;
default:
proto_tree_add_item(tree, hf_btavdtp_data, tvb, offset, losc, ENC_NA);
}
break;
case MEDIA_TYPE_VIDEO:
switch(media_codec_type) {
case CODEC_H263_BASELINE:
case CODEC_H263_PROFILE_3:
case CODEC_H263_PROFILE_8:
proto_tree_add_item(tree, hf_btavdtp_h263_level_10, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_h263_level_20, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_h263_level_30, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_h263_level_rfa, tvb, offset, 1, ENC_BIG_ENDIAN);
break;
case CODEC_MPEG4_VSP:
proto_tree_add_item(tree, hf_btavdtp_mpeg4_level_0, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg4_level_1, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg4_level_2, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg4_level_3, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_mpeg4_level_rfa, tvb, offset, 1, ENC_BIG_ENDIAN);
break;
case CODEC_VENDOR: /* non-VDP */
proto_tree_add_item(tree, hf_btavdtp_vendor_id, tvb, offset, 4, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_vendor_specific_codec_id, tvb, offset + 4, 2, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_btavdtp_vendor_specific_value, tvb, offset + 6, losc - 6, ENC_NA);
break;
default:
proto_tree_add_item(tree, hf_btavdtp_data, tvb, offset, losc, ENC_NA);
}
break;
default:
proto_tree_add_item(tree, hf_btavdtp_data, tvb, offset, losc, ENC_NA);
}
offset += losc;
return offset;
}
static gint
dissect_capabilities(tvbuff_t *tvb, packet_info *pinfo,
proto_tree *tree, gint offset, gint *codec,
gint *content_protection_type)
{
proto_item *pitem = NULL;
proto_item *ptree = NULL;
proto_tree *capabilities_tree;
proto_item *capabilities_item;
proto_tree *service_tree = NULL;
proto_item *service_item = NULL;
gint service_category = 0;
gint losc = 0;
gint recovery_type = 0;
gint maximum_recovery_window_size = 0;
gint maximum_number_of_media_packet_in_parity_code = 0;
gint media_type = 0;
gint media_codec_type = 0;
capabilities_item = proto_tree_add_item(tree, hf_btavdtp_capabilities, tvb, offset, tvb_length(tvb) - offset, ENC_NA);
capabilities_tree = proto_item_add_subtree(capabilities_item, ett_btavdtp_capabilities);
if (codec) {
*codec = -1;
}
while (tvb_length_remaining(tvb, offset) > 0) {
service_category = tvb_get_guint8(tvb, offset);
losc = tvb_get_guint8(tvb, offset + 1);
service_item = proto_tree_add_none_format(capabilities_tree, hf_btavdtp_service, tvb, offset, 2 + losc, "Service: %s", val_to_str_const(service_category, service_category_vals, "RFD"));
service_tree = proto_item_add_subtree(service_item, ett_btavdtp_service);
proto_tree_add_item(service_tree, hf_btavdtp_service_category, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
proto_tree_add_item(service_tree, hf_btavdtp_length_of_service_category, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
switch (service_category) {
case SERVICE_CATEGORY_MEDIA_TRANSPORT:
case SERVICE_CATEGORY_REPORTING:
case SERVICE_CATEGORY_DELAY_REPORTING:
/* losc should be 0*/
break;
case SERVICE_CATEGORY_RECOVERY:
recovery_type = tvb_get_guint8(tvb, offset);
pitem = proto_tree_add_item(service_tree, hf_btavdtp_recovery_type, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_item_append_text(pitem, " (%s)", val_to_str_const(recovery_type, recovery_type_vals, "RFD"));
offset += 1;
losc -= 1;
maximum_recovery_window_size = tvb_get_guint8(tvb, offset);
pitem = proto_tree_add_item(service_tree, hf_btavdtp_maximum_recovery_window_size, tvb, offset, 1, ENC_BIG_ENDIAN);
if (maximum_recovery_window_size == 0x00) {
proto_item_append_text(pitem, " (Forbidden)");
} else if (maximum_recovery_window_size >= 0x18) {
proto_item_append_text(pitem, " (Undocumented)");
}
offset += 1;
losc -= 1;
maximum_number_of_media_packet_in_parity_code = tvb_get_guint8(tvb, offset);
proto_tree_add_item(service_tree, hf_btavdtp_maximum_number_of_media_packet_in_parity_code, tvb, offset, 1, ENC_BIG_ENDIAN);
pitem = proto_tree_add_item(service_tree, hf_btavdtp_maximum_recovery_window_size, tvb, offset, 1, ENC_BIG_ENDIAN);
if (maximum_number_of_media_packet_in_parity_code == 0x00) {
proto_item_append_text(pitem, " (Forbidden)");
} else if (maximum_number_of_media_packet_in_parity_code >= 0x18) {
proto_item_append_text(pitem, " (Undocumented)");
}
offset += 1;
losc -= 1;
break;
case SERVICE_CATEGORY_MEDIA_CODEC:
media_type = tvb_get_guint8(tvb, offset) >> 4;
proto_tree_add_item(service_tree, hf_btavdtp_media_codec_media_type, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(service_tree, hf_btavdtp_media_codec_rfa , tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
losc -= 1;
media_codec_type = tvb_get_guint8(tvb, offset);
if (codec) {
*codec = media_codec_type;
}
if (media_type == MEDIA_TYPE_AUDIO) {
proto_tree_add_item(service_tree, hf_btavdtp_media_codec_audio_type, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_item_append_text(service_item, " - Audio %s",
val_to_str_const(media_codec_type, media_codec_audio_type_vals, "unknown codec"));
col_append_fstr(pinfo->cinfo, COL_INFO, " - Audio %s",
val_to_str_const(media_codec_type, media_codec_audio_type_vals, "unknown codec"));
} else if (media_type == MEDIA_TYPE_VIDEO) {
proto_tree_add_item(service_tree, hf_btavdtp_media_codec_video_type, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_item_append_text(service_item, " - Video %s",
val_to_str_const(media_codec_type, media_codec_video_type_vals, "unknown codec"));
col_append_fstr(pinfo->cinfo, COL_INFO, " - Video %s",
val_to_str_const(media_codec_type, media_codec_video_type_vals, "unknown codec"));
} else {
proto_tree_add_item(service_tree, hf_btavdtp_media_codec_unknown_type, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_item_append_text(service_item, " - Unknown 0x%02x", media_codec_type);
col_append_fstr(pinfo->cinfo, COL_INFO, " - Unknown 0x%02x", media_codec_type);
}
offset += 1;
losc -= 1;
offset = dissect_codec(tvb, pinfo, service_tree, offset, losc, media_type, media_codec_type);
losc = 0;
break;
case SERVICE_CATEGORY_CONTENT_PROTECTION:
/* ENC_LITTLE_ENDIAN is correct here... */
proto_tree_add_item(service_tree, hf_btavdtp_content_protection_type, tvb, offset, 2, ENC_LITTLE_ENDIAN);
if (content_protection_type) {
*content_protection_type = tvb_get_letohs(tvb, offset);
}
offset += 2;
losc -= 2;
if (losc > 0) {
proto_tree_add_item(service_tree, hf_btavdtp_data, tvb, offset, losc, ENC_NA);
offset += losc;
losc = 0;
}
break;
case SERVICE_CATEGORY_HEADER_COMPRESSION:
proto_tree_add_item(service_tree, hf_btavdtp_header_compression_backch, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(service_tree, hf_btavdtp_header_compression_media, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(service_tree, hf_btavdtp_header_compression_recovery, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(service_tree, hf_btavdtp_header_compression_rfa, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
losc -= 1;
break;
case SERVICE_CATEGORY_MULTIPLEXING:
proto_tree_add_item(service_tree, hf_btavdtp_multiplexing_fragmentation, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(service_tree, hf_btavdtp_multiplexing_rfa, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
losc -= 1;
if (losc >= 2) {
pitem = proto_tree_add_none_format(service_tree, hf_btavdtp_service_multiplexing_entry, tvb, offset, 1 + losc, "Entry: Media Transport Session");
ptree = proto_item_add_subtree(pitem, ett_btavdtp_service);
proto_tree_add_item(ptree, hf_btavdtp_multiplexing_tsid, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(ptree, hf_btavdtp_multiplexing_entry_rfa, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
losc -= 1;
proto_tree_add_item(ptree, hf_btavdtp_multiplexing_tcid, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(ptree, hf_btavdtp_multiplexing_entry_rfa, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
losc -= 1;
}
if (losc >= 2) {
pitem = proto_tree_add_none_format(service_tree, hf_btavdtp_service_multiplexing_entry, tvb, offset, 1 + losc, "Entry: Reporting Transport Session");
ptree = proto_item_add_subtree(pitem, ett_btavdtp_service);
proto_tree_add_item(ptree, hf_btavdtp_multiplexing_tsid, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(ptree, hf_btavdtp_multiplexing_entry_rfa, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
losc -= 1;
proto_tree_add_item(ptree, hf_btavdtp_multiplexing_tcid, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(ptree, hf_btavdtp_multiplexing_entry_rfa, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
losc -= 1;
}
if (losc >= 2) {
pitem = proto_tree_add_none_format(service_tree, hf_btavdtp_service_multiplexing_entry, tvb, offset, 1 + losc, "Entry: Recovery Transport Session");
ptree = proto_item_add_subtree(pitem, ett_btavdtp_service);
proto_tree_add_item(ptree, hf_btavdtp_multiplexing_tsid, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(ptree, hf_btavdtp_multiplexing_entry_rfa, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
losc -= 1;
proto_tree_add_item(ptree, hf_btavdtp_multiplexing_tcid, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(ptree, hf_btavdtp_multiplexing_entry_rfa, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
losc -= 1;
}
break;
default:
proto_tree_add_item(service_tree, hf_btavdtp_data, tvb, offset, losc, ENC_NA);
offset += losc;
losc = 0;
}
if (losc > 0) {
pitem = proto_tree_add_item(service_tree, hf_btavdtp_data, tvb, offset, losc, ENC_NA);
offset += losc;
expert_add_info(pinfo, pitem, &ei_btavdtp_unexpected_losc_data);
}
}
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)
{
guint32 seid;
proto_tree *seid_tree = NULL;
proto_item *seid_item = NULL;
seid = tvb_get_guint8(tvb, offset) >> 2;
if (sep_seid) {
*sep_seid = seid;
}
if (seid_side == SEID_ACP) {
seid_item = proto_tree_add_none_format(tree, hf_btavdtp_acp_seid_item, tvb, offset, 1,
"ACP SEID [%u - %s %s]", seid, get_sep_media_type(pinfo->fd->num, seid), get_sep_type(pinfo->fd->num, seid));
seid_tree = proto_item_add_subtree(seid_item, ett_btavdtp_sep);
proto_tree_add_item(seid_tree, hf_btavdtp_acp_seid, tvb, offset, 1, ENC_BIG_ENDIAN);
if (i_item > 0) proto_item_append_text(seid_item, " item %u", i_item);
col_append_fstr(pinfo->cinfo, COL_INFO, " - ACP SEID [%u - %s %s]",
seid, get_sep_media_type(pinfo->fd->num, seid), get_sep_type(pinfo->fd->num, seid));
} else {
seid_item = proto_tree_add_none_format(tree, hf_btavdtp_int_seid_item, tvb, offset, 1,
"INT SEID [%u - %s %s]", seid, get_sep_media_type(pinfo->fd->num, seid), get_sep_type(pinfo->fd->num, seid));
seid_tree = proto_item_add_subtree(seid_item, ett_btavdtp_sep);
proto_tree_add_item(seid_tree, hf_btavdtp_int_seid, tvb, offset, 1, ENC_BIG_ENDIAN);
if (i_item > 0) proto_item_append_text(seid_item, " item %u", i_item);
col_append_fstr(pinfo->cinfo, COL_INFO, " - INT SEID [%u - %s %s]",
seid, get_sep_media_type(pinfo->fd->num, seid), get_sep_type(pinfo->fd->num, seid));
}
proto_tree_add_item(seid_tree, hf_btavdtp_rfa_seid, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
return offset;
}
static gint
dissect_btavdtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
{
proto_item *ti;
proto_tree *btavdtp_tree = NULL;
proto_tree *signal_tree = NULL;
proto_item *signal_item = NULL;
btl2cap_data_t *l2cap_data;
gint offset = 0;
gint i_sep = 1;
gint packet_type = 0;
gint message_type = 0;
gint signal_id = 0;
guint delay;
wmem_tree_key_t key[4];
guint32 t_type;
guint32 t_cid;
guint32 t_frame_number;
cid_type_data_t *cid_type_data;
sep_entry_t *sep;
tvbuff_t *next_tvb;
guint32 seid;
guint32 t_seid;
gint codec = -1;
gint content_protection_type = 0;
col_set_str(pinfo->cinfo, COL_PROTOCOL, "AVDTP");
switch (pinfo->p2p_dir) {
case P2P_DIR_SENT:
col_set_str(pinfo->cinfo, COL_INFO, "Sent ");
break;
case P2P_DIR_RECV:
col_set_str(pinfo->cinfo, COL_INFO, "Rcvd ");
break;
default:
col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown direction %d ",
pinfo->p2p_dir);
goto LABEL_data;
break;
}
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->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 {
sep = (sep_entry_t *)wmem_tree_lookup32_le(sep_open, pinfo->fd->num);
if (sep && sep->state == SEP_STATE_OPEN) {
sep->state = SEP_STATE_IN_USE;
cid_type_data->sep = sep;
}
}
t_type = cid_type_data->type;
t_cid = cid_type_data->cid;
t_frame_number = pinfo->fd->num;
key[0].length = 1;
key[0].key = &t_cid;
key[1].length = 1;
key[1].key = &t_type;
key[2].length = 1;
key[2].key = &t_frame_number;
key[3].length = 0;
key[3].key = NULL;
wmem_tree_insert32_array(cid_to_type_table, key, cid_type_data);
}
if (!force_avdtp) {
t_type = STREAM_TYPE_SIGNAL;
t_cid = l2cap_data->cid;
t_frame_number = pinfo->fd->num;
key[0].length = 1;
key[0].key = &t_cid;
key[1].length = 1;
key[1].key = &t_type;
key[2].length = 1;
key[2].key = &t_frame_number;
key[3].length = 0;
key[3].key = NULL;
cid_type_data = (cid_type_data_t *)wmem_tree_lookup32_array_le(cid_to_type_table, key);
if (cid_type_data && cid_type_data->type == STREAM_TYPE_MEDIA && cid_type_data->cid == l2cap_data->cid) {
/* AVDTP Media */
if (!cid_type_data->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]",
cid_type_data->sep->seid, get_sep_media_type(pinfo->fd->num, cid_type_data->sep->seid),
get_sep_type(pinfo->fd->num, cid_type_data->sep->seid));
if (cid_type_data->sep->media_type == MEDIA_TYPE_AUDIO) {
sep_data_t sep_data;
sep_data.codec = cid_type_data->sep->codec;
sep_data.content_protection_type = cid_type_data->sep->content_protection_type;
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.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 && cid_type_data->cid == l2cap_data->cid)) {
/* 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);
}
}
ti = proto_tree_add_item(tree, proto_btavdtp, tvb, offset, -1, ENC_NA);
btavdtp_tree = proto_item_add_subtree(ti, ett_btavdtp);
/* AVDTP signaling*/
message_type = (tvb_get_guint8(tvb, offset) & AVDTP_MESSAGE_TYPE_MASK);
packet_type = (tvb_get_guint8(tvb, offset) & AVDTP_PACKET_TYPE_MASK) >> 2;
signal_item = proto_tree_add_item(btavdtp_tree, hf_btavdtp_signal, tvb, offset,
(packet_type == PACKET_TYPE_START) ? 3 : 2, ENC_NA);
signal_tree = proto_item_add_subtree(signal_item, ett_btavdtp_sep);
proto_tree_add_item(signal_tree, hf_btavdtp_transaction, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(signal_tree, hf_btavdtp_packet_type, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(signal_tree, hf_btavdtp_message_type, tvb, offset, 1, ENC_BIG_ENDIAN);
if (packet_type == PACKET_TYPE_START) {
offset += 1;
proto_tree_add_item(signal_tree, hf_btavdtp_number_of_signal_packets, tvb, offset, 1, ENC_BIG_ENDIAN);
}
if (packet_type == PACKET_TYPE_CONTINUE || packet_type == PACKET_TYPE_END) goto LABEL_data;
offset += 1;
proto_tree_add_item(signal_tree, hf_btavdtp_rfa0, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(signal_tree, hf_btavdtp_signal_id, tvb, offset, 1, ENC_BIG_ENDIAN);
signal_id = tvb_get_guint8(tvb, offset) & AVDTP_SIGNAL_ID_MASK;
proto_item_append_text(signal_item, ": %s (%s)",
val_to_str_const(signal_id, signal_id_vals, "Unknown signal"),
val_to_str_const(message_type, message_type_vals, "Unknown message type"));
col_append_fstr(pinfo->cinfo, COL_INFO, "%s - %s",
val_to_str_const(message_type, message_type_vals, "Unknown message type"),
val_to_str_const(signal_id, signal_id_vals, "Unknown signal"));
offset += 1;
if (message_type != MESSAGE_TYPE_GENERAL_REJECT) switch (signal_id) {
case SIGNAL_ID_DISCOVER:
if (message_type == MESSAGE_TYPE_COMMAND) break;
if (message_type == MESSAGE_TYPE_REJECT) {
proto_tree_add_item(btavdtp_tree, hf_btavdtp_error_code, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
break;
}
offset = dissect_sep(tvb, pinfo, btavdtp_tree, offset);
break;
case SIGNAL_ID_GET_CAPABILITIES:
case SIGNAL_ID_GET_ALL_CAPABILITIES:
if (message_type == MESSAGE_TYPE_COMMAND) {
offset = dissect_seid(tvb, pinfo, btavdtp_tree, offset, SEID_ACP, 0, NULL);
break;
}
if (message_type == MESSAGE_TYPE_REJECT) {
proto_tree_add_item(btavdtp_tree, hf_btavdtp_error_code, tvb, offset, 1, ENC_BIG_ENDIAN);
break;
}
offset = dissect_capabilities(tvb, pinfo, btavdtp_tree, offset, NULL, NULL);
break;
case SIGNAL_ID_SET_CONFIGURATION:
if (message_type == MESSAGE_TYPE_COMMAND) {
offset = dissect_seid(tvb, pinfo, btavdtp_tree, offset, SEID_ACP, 0, &seid);
offset = dissect_seid(tvb, pinfo, btavdtp_tree, offset, SEID_INT, 0, NULL);
offset = dissect_capabilities(tvb, pinfo, btavdtp_tree, offset, &codec, &content_protection_type);
t_frame_number = pinfo->fd->num;
t_seid = seid;
key[0].length = 1;
key[0].key = &t_seid;
key[1].length = 1;
key[1].key = &t_frame_number;
key[2].length = 0;
key[2].key = NULL;
sep = (sep_entry_t *)wmem_tree_lookup32_array_le(sep_list, key);
if (sep && sep->seid == seid) {
sep->codec = codec;
sep->content_protection_type = content_protection_type;
}
break;
}
if (message_type == MESSAGE_TYPE_REJECT) {
proto_tree_add_item(btavdtp_tree, hf_btavdtp_service_category, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
proto_tree_add_item(btavdtp_tree, hf_btavdtp_error_code, tvb, offset, 1, ENC_BIG_ENDIAN);
break;
}
break;
case SIGNAL_ID_GET_CONFIGURATION:
if (message_type == MESSAGE_TYPE_COMMAND) {
offset = dissect_seid(tvb, pinfo, btavdtp_tree, offset, SEID_ACP, 0, NULL);
break;
}
if (message_type == MESSAGE_TYPE_REJECT) {
proto_tree_add_item(btavdtp_tree, hf_btavdtp_error_code, tvb, offset, 1, ENC_BIG_ENDIAN);
break;
}
offset = dissect_capabilities(tvb, pinfo, btavdtp_tree, offset, NULL, NULL);
break;
case SIGNAL_ID_RECONFIGURE:
if (message_type == MESSAGE_TYPE_COMMAND) {
offset = dissect_seid(tvb, pinfo, btavdtp_tree, offset, SEID_ACP, 0, &seid);
offset = dissect_capabilities(tvb, pinfo, btavdtp_tree, offset, &codec, &content_protection_type);
t_frame_number = pinfo->fd->num;
t_seid = seid;
key[0].length = 1;
key[0].key = &t_seid;
key[1].length = 1;
key[1].key = &t_frame_number;
key[2].length = 0;
key[2].key = NULL;
sep = (sep_entry_t *)wmem_tree_lookup32_array_le(sep_list, key);
if (sep && sep->seid == seid) {
sep->codec = codec;
sep->content_protection_type = content_protection_type;
}
break;
}
if (message_type == MESSAGE_TYPE_REJECT) {
proto_tree_add_item(btavdtp_tree, hf_btavdtp_service_category, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
proto_tree_add_item(btavdtp_tree, hf_btavdtp_error_code, tvb, offset, 1, ENC_BIG_ENDIAN);
break;
}
break;
case SIGNAL_ID_OPEN:
if (message_type == MESSAGE_TYPE_COMMAND) {
offset = dissect_seid(tvb, pinfo, btavdtp_tree, offset, SEID_ACP, 0, &seid);
t_frame_number = pinfo->fd->num;
t_seid = seid;
key[0].length = 1;
key[0].key = &t_seid;
key[1].length = 1;
key[1].key = &t_frame_number;
key[2].length = 0;
key[2].key = NULL;
sep = (sep_entry_t *)wmem_tree_lookup32_array_le(sep_list, key);
if (sep && sep->seid == seid) {
sep->state = SEP_STATE_OPEN;
}
wmem_tree_insert32(sep_open, pinfo->fd->num, sep);
break;
}
if (message_type == MESSAGE_TYPE_REJECT) {
proto_tree_add_item(btavdtp_tree, hf_btavdtp_error_code, tvb, offset, 1, ENC_BIG_ENDIAN);
break;
}
break;
case SIGNAL_ID_START:
if (message_type == MESSAGE_TYPE_COMMAND) {
i_sep = 1;
while (tvb_length_remaining(tvb, offset) > 0) {
offset = dissect_seid(tvb, pinfo, btavdtp_tree, offset, SEID_ACP, i_sep, NULL);
i_sep += 1;
}
break;
}
if (message_type == MESSAGE_TYPE_REJECT) {
offset = dissect_seid(tvb, pinfo, btavdtp_tree, offset, SEID_ACP, 0, NULL);
proto_tree_add_item(btavdtp_tree, hf_btavdtp_error_code, tvb, offset, 1, ENC_BIG_ENDIAN);
break;
}
break;
case SIGNAL_ID_CLOSE:
if (message_type == MESSAGE_TYPE_COMMAND) {
offset = dissect_seid(tvb, pinfo, btavdtp_tree, offset, SEID_ACP, 0, NULL);
break;
}
if (message_type == MESSAGE_TYPE_REJECT) {
proto_tree_add_item(btavdtp_tree, hf_btavdtp_error_code, tvb, offset, 1, ENC_BIG_ENDIAN);
break;
}
break;
case SIGNAL_ID_SUSPEND:
if (message_type == MESSAGE_TYPE_COMMAND) {
i_sep = 1;
while (tvb_length_remaining(tvb, offset) > 0) {
offset = dissect_seid(tvb, pinfo, btavdtp_tree, offset, SEID_ACP, i_sep, NULL);
i_sep += 1;
}
break;
}
if (message_type == MESSAGE_TYPE_REJECT) {
offset = dissect_seid(tvb, pinfo, btavdtp_tree, offset, SEID_ACP, 0, NULL);
proto_tree_add_item(btavdtp_tree, hf_btavdtp_error_code, tvb, offset, 1, ENC_BIG_ENDIAN);
break;
}
break;
case SIGNAL_ID_ABORT:
if (message_type == MESSAGE_TYPE_COMMAND) {
offset = dissect_seid(tvb, pinfo, btavdtp_tree, offset, SEID_ACP, 0, NULL);
break;
}
if (message_type == MESSAGE_TYPE_REJECT) {
proto_tree_add_item(btavdtp_tree, hf_btavdtp_error_code, tvb, offset, 1, ENC_BIG_ENDIAN);
break;
}
break;
case SIGNAL_ID_SECURITY_CONTROL:
if (message_type == MESSAGE_TYPE_COMMAND) {
offset = dissect_seid(tvb, pinfo, btavdtp_tree, offset, SEID_ACP, 0, NULL);
proto_tree_add_item(btavdtp_tree, hf_btavdtp_data, tvb, offset, -1, ENC_NA);
offset += tvb_length_remaining(tvb, offset);
break;
}
if (message_type == MESSAGE_TYPE_REJECT) {
proto_tree_add_item(btavdtp_tree, hf_btavdtp_error_code, tvb, offset, 1, ENC_BIG_ENDIAN);
break;
}
proto_tree_add_item(btavdtp_tree, hf_btavdtp_data, tvb, offset, -1, ENC_NA);
offset += tvb_length_remaining(tvb, offset);
break;
case SIGNAL_ID_DELAY_REPORT:
if (message_type == MESSAGE_TYPE_COMMAND) {
proto_item *pitem;
delay = tvb_get_ntohs(tvb, offset + 1);
col_append_fstr(pinfo->cinfo, COL_INFO, "(%u.%u ms)", delay/10, delay%10);
offset = dissect_seid(tvb, pinfo, btavdtp_tree, offset, SEID_ACP, 0, NULL);
pitem = proto_tree_add_item(btavdtp_tree, hf_btavdtp_delay, tvb, offset, 2, ENC_BIG_ENDIAN);
proto_item_append_text(pitem, " (1/10 ms)");
offset += 2;
break;
}
if (message_type == MESSAGE_TYPE_REJECT) {
proto_tree_add_item(btavdtp_tree, hf_btavdtp_error_code, tvb, offset, 1, ENC_BIG_ENDIAN);
break;
}
break;
}
LABEL_data:
if (tvb_length_remaining(tvb, offset) > 0) {
proto_tree_add_item(btavdtp_tree, hf_btavdtp_data, tvb, offset, -1, ENC_NA);
}
return offset;
}
void
proto_register_btavdtp(void)
{
module_t *module;
static hf_register_info hf[] = {
{ &hf_btavdtp_signal,
{ "Signal", "btavdtp.signal",
FT_NONE, BASE_NONE, NULL, 0x00,
NULL, HFILL }
},
{ &hf_btavdtp_message_type,
{ "Message Type", "btavdtp.message_type",
FT_UINT8, BASE_HEX, VALS(message_type_vals), AVDTP_MESSAGE_TYPE_MASK,
NULL, HFILL }
},
{ &hf_btavdtp_packet_type,
{ "Packet Type", "btavdtp.packet_type",
FT_UINT8, BASE_HEX, VALS(packet_type_vals), AVDTP_PACKET_TYPE_MASK,
NULL, HFILL }
},
{ &hf_btavdtp_transaction,
{ "Transaction", "btavdtp.transaction",
FT_UINT8, BASE_HEX, NULL, AVDTP_TRANSACTION_MASK,
NULL, HFILL }
},
{ &hf_btavdtp_signal_id,
{ "Signal", "btavdtp.signal_id",
FT_UINT8, BASE_HEX, VALS(signal_id_vals), AVDTP_SIGNAL_ID_MASK,
NULL, HFILL }
},
{ &hf_btavdtp_rfa0,
{ "RFA", "btavdtp.rfa0",
FT_UINT8, BASE_HEX, NULL, AVDTP_RFA0_MASK,
NULL, HFILL }
},
{ &hf_btavdtp_number_of_signal_packets,
{ "Number of signal packets", "btavdtp.num_signal_packets",
FT_UINT8, BASE_DEC, NULL, 0,
NULL, HFILL }
},
{ &hf_btavdtp_error_code,
{ "Error Code", "btavdtp.error_code",
FT_UINT8, BASE_HEX, VALS(error_code_vals), 0x00,
NULL, HFILL }
},
{ &hf_btavdtp_sep_seid,
{ "SEID", "btavdtp.sep_seid",
FT_UINT8, BASE_DEC, NULL, 0xFC,
NULL, HFILL }
},
{ &hf_btavdtp_sep_inuse,
{ "In Use", "btavdtp.sep_inuse",
FT_UINT8, BASE_HEX, VALS(true_false), 0x02,
NULL, HFILL }
},
{ &hf_btavdtp_sep_rfa0,
{ "RFA0", "btavdtp.sep_rfa0",
FT_UINT8, BASE_HEX, NULL, 0x01,
NULL, HFILL }
},
{ &hf_btavdtp_sep_media_type,
{ "Media Type", "btavdtp.sep_media_type",
FT_UINT8, BASE_HEX, VALS(media_type_vals), 0xF0,
NULL, HFILL }
},
{ &hf_btavdtp_sep_type,
{ "Type", "btavdtp.sep_type",
FT_UINT8, BASE_HEX, VALS(sep_type_vals), 0x08,
NULL, HFILL }
},
{ &hf_btavdtp_sep_rfa1,
{ "RFA1", "btavdtp.sep_rfa1",
FT_UINT8, BASE_HEX, NULL, 0x07,
NULL, HFILL }
},
{ &hf_btavdtp_acp_sep,
{ "ACP SEP", "btavdtp.acp_sep",
FT_NONE, BASE_NONE, NULL, 0x00,
NULL, HFILL }
},
{ &hf_btavdtp_acp_seid_item,
{ "ACP SEID", "btavdtp.acp_seid_item",
FT_NONE, BASE_NONE, NULL, 0x00,
NULL, HFILL }
},
{ &hf_btavdtp_int_seid_item,
{ "INT SEID", "btavdtp.int_seid_item",
FT_NONE, BASE_NONE, NULL, 0x00,
NULL, HFILL }
},
{ &hf_btavdtp_acp_seid,
{ "ACP SEID", "btavdtp.acp_seid",
FT_UINT8, BASE_DEC, NULL, 0xFC,
NULL, HFILL }
},
{ &hf_btavdtp_int_seid,
{ "INT SEID", "btavdtp.int_seid",
FT_UINT8, BASE_DEC, NULL, 0xFC,
NULL, HFILL }
},
{ &hf_btavdtp_rfa_seid,
{ "RFA", "btavdtp.rfa_seid",
FT_UINT8, BASE_HEX, NULL, 0x03,
NULL, HFILL }
},
{ &hf_btavdtp_service_category,
{ "Service Category", "btavdtp.service_category",
FT_UINT8, BASE_HEX, VALS(service_category_vals), 0x00,
NULL, HFILL }
},
{ &hf_btavdtp_length_of_service_category,
{ "Length of Service Category", "btavdtp.length_of_service_category",
FT_UINT8, BASE_HEX, NULL, 0x00,
NULL, HFILL }
},
{ &hf_btavdtp_delay,
{ "Delay", "btavdtp.delay",
FT_UINT16, BASE_DEC, NULL, 0x00,
NULL, HFILL }
},
{ &hf_btavdtp_recovery_type,
{ "Service Category", "btavdtp.recovery_type",
FT_UINT8, BASE_HEX, VALS(recovery_type_vals), 0x00,
NULL, HFILL }
},
{ &hf_btavdtp_maximum_recovery_window_size,
{ "Service Category", "btavdtp.maximum_recovery_window_size",
FT_UINT8, BASE_HEX, NULL, 0x00,
NULL, HFILL }
},
{ &hf_btavdtp_maximum_number_of_media_packet_in_parity_code,
{ "Service Category", "btavdtp.maximum_number_of_media_packet_in_parity_code",
FT_UINT8, BASE_HEX, NULL, 0x00,
NULL, HFILL }
},
{ &hf_btavdtp_multiplexing_fragmentation,
{ "Fragmentation", "btavdtp.multiplexing_fragmentation",
FT_UINT8, BASE_HEX, VALS(true_false), 0x80,
NULL, HFILL }
},
{ &hf_btavdtp_multiplexing_rfa,
{ "RFA", "btavdtp.multiplexing_rfa",
FT_UINT8, BASE_HEX, NULL, 0x7F,
NULL, HFILL }
},
{ &hf_btavdtp_multiplexing_tsid,
{ "TSID", "btavdtp.multiplexing_tsid",
FT_UINT8, BASE_HEX, VALS(multiplexing_tsid_vals), 0xF8,
NULL, HFILL }
},
{ &hf_btavdtp_multiplexing_tcid,
{ "TCID", "btavdtp.multiplexing_tcid",
FT_UINT8, BASE_HEX, VALS(multiplexing_tcid_vals), 0xF8,
NULL, HFILL }
},
{ &hf_btavdtp_multiplexing_entry_rfa,
{ "RFA", "btavdtp.multiplexing_entry_rfa",
FT_UINT8, BASE_HEX, NULL, 0x07,
NULL, HFILL }
},
{ &hf_btavdtp_header_compression_backch,
{ "BackCh", "btavdtp.header_compression_backch",
FT_UINT8, BASE_HEX, VALS(true_false), 0x80,
NULL, HFILL }
},
{ &hf_btavdtp_header_compression_media,
{ "Media", "btavdtp.header_compression_media",
FT_UINT8, BASE_HEX, VALS(true_false), 0x40,
NULL, HFILL }
},
{ &hf_btavdtp_header_compression_recovery,
{ "Recovery", "btavdtp.header_compression_recovery",
FT_UINT8, BASE_HEX, VALS(true_false), 0x20,
NULL, HFILL }
},
{ &hf_btavdtp_header_compression_rfa,
{ "RFA", "btavdtp.header_compression_rfa",
FT_UINT8, BASE_HEX, NULL, 0x1f,
NULL, HFILL }
},
{ &hf_btavdtp_content_protection_type,
{ "Type", "btavdtp.content_protection_type",
FT_UINT16, BASE_HEX, VALS(content_protection_type_vals), 0x0000,
NULL, HFILL }
},
{ &hf_btavdtp_media_codec_media_type,
{ "Media Type", "btavdtp.media_codec_media_type",
FT_UINT8, BASE_HEX, VALS(media_type_vals), 0xF0,
NULL, HFILL }
},
{ &hf_btavdtp_media_codec_rfa,
{ "RFA", "btavdtp.media_codec_rfa",
FT_UINT8, BASE_HEX, NULL, 0x0F,
NULL, HFILL }
},
{ &hf_btavdtp_media_codec_audio_type,
{ "Media Codec Audio Type", "btavdtp.media_codec_audio_type",
FT_UINT8, BASE_HEX, VALS(media_codec_audio_type_vals), 0x00,
NULL, HFILL }
},
{ &hf_btavdtp_media_codec_video_type,
{ "Media Codec Video Type", "btavdtp.media_codec_video_type",
FT_UINT8, BASE_HEX, VALS(media_codec_video_type_vals), 0x00,
NULL, HFILL }
},
{ &hf_btavdtp_media_codec_unknown_type,
{ "Media Codec Unknown Type", "btavdtp.media_codec_unknown_type",
FT_UINT8, BASE_HEX, NULL, 0x00,
NULL, HFILL }
},
{ &hf_btavdtp_sbc_sampling_frequency_16000,
{ "Sampling Frequency 16000 Hz", "btavdtp.codec.sbc.sampling_frequency.16000",
FT_BOOLEAN, 8, NULL, 0x80,
NULL, HFILL }
},
{ &hf_btavdtp_sbc_sampling_frequency_32000,
{ "Sampling Frequency 32000 Hz", "btavdtp.codec.sbc.sampling_frequency.32000",
FT_BOOLEAN, 8, NULL, 0x40,
NULL, HFILL }
},
{ &hf_btavdtp_sbc_sampling_frequency_44100,
{ "Sampling Frequency 44100 Hz", "btavdtp.codec.sbc.sampling_frequency.44100",
FT_BOOLEAN, 8, NULL, 0x20,
NULL, HFILL }
},
{ &hf_btavdtp_sbc_sampling_frequency_48000,
{ "Sampling Frequency 48000 Hz", "btavdtp.codec.sbc.sampling_frequency.48000",
FT_BOOLEAN, 8, NULL, 0x10,
NULL, HFILL }
},
{ &hf_btavdtp_sbc_channel_mode_mono,
{ "Channel Mode Mono", "btavdtp.codec.sbc.channel_mode.mono",
FT_BOOLEAN, 8, NULL, 0x08,
NULL, HFILL }
},
{ &hf_btavdtp_sbc_channel_mode_dual_channel,
{ "Channel Mode Dual Channel", "btavdtp.codec.sbc.channel_mode.dual_channel",
FT_BOOLEAN, 8, NULL, 0x04,
NULL, HFILL }
},
{ &hf_btavdtp_sbc_channel_mode_stereo,
{ "Channel Mode Stereo", "btavdtp.codec.sbc.channel_mode.stereo",
FT_BOOLEAN, 8, NULL, 0x02,
NULL, HFILL }
},
{ &hf_btavdtp_sbc_channel_mode_joint_stereo,
{ "Channel Mode Joint Stereo", "btavdtp.codec.sbc.channel_mode.joint_stereo",
FT_BOOLEAN, 8, NULL, 0x01,
NULL, HFILL }
},
{ &hf_btavdtp_sbc_block_4,
{ "Block Length 4", "btavdtp.codec.sbc.block_4",
FT_BOOLEAN, 8, NULL, 0x80,
NULL, HFILL }
},
{ &hf_btavdtp_sbc_block_8,
{ "Block Length 8", "btavdtp.codec.sbc.block_8",
FT_BOOLEAN, 8, NULL, 0x40,
NULL, HFILL }
},
{ &hf_btavdtp_sbc_block_12,
{ "Block Length 12", "btavdtp.codec.sbc.block_12",
FT_BOOLEAN, 8, NULL, 0x20,
NULL, HFILL }
},
{ &hf_btavdtp_sbc_block_16,
{ "Block Length 16", "btavdtp.codec.sbc.block_16",
FT_BOOLEAN, 8, NULL, 0x10,
NULL, HFILL }
},
{ &hf_btavdtp_sbc_subbands_4,
{ "Subbands 4", "btavdtp.codec.sbc.subbands_4",
FT_BOOLEAN, 8, NULL, 0x08,
NULL, HFILL }
},
{ &hf_btavdtp_sbc_subbands_8,
{ "Subbands 8", "btavdtp.codec.sbc.subbands_8",
FT_BOOLEAN, 8, NULL, 0x04,
NULL, HFILL }
},
{ &hf_btavdtp_sbc_allocation_method_snr,
{ "Allocation Method SNR", "btavdtp.codec.sbc.allocation_method_snr",
FT_BOOLEAN, 8, NULL, 0x02,
NULL, HFILL }
},
{ &hf_btavdtp_sbc_allocation_method_loudness,
{ "Allocation Method Loudness", "btavdtp.codec.sbc.allocation_method_loudness",
FT_BOOLEAN, 8, NULL, 0x01,
NULL, HFILL }
},
{ &hf_btavdtp_sbc_min_bitpool,
{ "Minumum Bitpool", "btavdtp.codec.sbc.minimum_bitpool",
FT_UINT8, BASE_DEC, NULL, 0x00,
NULL, HFILL }
},
{ &hf_btavdtp_sbc_max_bitpool,
{ "Maximum Bitpool", "btavdtp.codec.sbc.maximum_bitpool",
FT_UINT8, BASE_DEC, NULL, 0x00,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg12_layer_1,
{ "MP1", "btavdtp.codec.mpeg12.layer_1",
FT_BOOLEAN, 8, NULL, 0x80,
"MPEG Layer 1", HFILL }
},
{ &hf_btavdtp_mpeg12_layer_2,
{ "MP2", "btavdtp.codec.mpeg12.layer_2",
FT_BOOLEAN, 8, NULL, 0x40,
"MPEG Layer 2", HFILL }
},
{ &hf_btavdtp_mpeg12_layer_3,
{ "MP3", "btavdtp.codec.mpeg12.layer_3",
FT_BOOLEAN, 8, NULL, 0x20,
"MPEG Layer 3", HFILL }
},
{ &hf_btavdtp_mpeg12_crc_protection,
{ "CRC Protection", "btavdtp.codec.mpeg12.crc_protection",
FT_BOOLEAN, 8, NULL, 0x10,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg12_channel_mode_mono,
{ "Channel Mode Mono", "btavdtp.codec.mpeg12.channel_mode.mono",
FT_BOOLEAN, 8, NULL, 0x08,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg12_channel_mode_dual_channel,
{ "Channel Mode Dual Channel", "btavdtp.codec.mpeg12.channel_mode.dual_channel",
FT_BOOLEAN, 8, NULL, 0x04,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg12_channel_mode_stereo,
{ "Channel Mode Stereo", "btavdtp.codec.mpeg12.channel_mode.stereo",
FT_BOOLEAN, 8, NULL, 0x02,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg12_channel_mode_joint_stereo,
{ "Channel Mode Joint Stereo", "btavdtp.codec.mpeg12.channel_mode.joint_stereo",
FT_BOOLEAN, 8, NULL, 0x01,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg12_rfa,
{ "RFA", "btavdtp.codec.mpeg12.rfa",
FT_BOOLEAN, 8, NULL, 0x80,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg12_mpf_2,
{ "MPF 2", "btavdtp.codec.mpeg12.mpf_2",
FT_BOOLEAN, 8, NULL, 0x40,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg12_sampling_frequency_16000,
{ "Sampling Frequency 16000 Hz", "btavdtp.codec.sbc.sampling_frequency.16000",
FT_BOOLEAN, 8, NULL, 0x20,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg12_sampling_frequency_22050,
{ "Sampling Frequency 22050 Hz", "btavdtp.codec.sbc.sampling_frequency.22050",
FT_BOOLEAN, 8, NULL, 0x10,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg12_sampling_frequency_24000,
{ "Sampling Frequency 24000 Hz", "btavdtp.codec.sbc.sampling_frequency.24000",
FT_BOOLEAN, 8, NULL, 0x08,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg12_sampling_frequency_32000,
{ "Sampling Frequency 32000 Hz", "btavdtp.codec.sbc.sampling_frequency.32000",
FT_BOOLEAN, 8, NULL, 0x04,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg12_sampling_frequency_44100,
{ "Sampling Frequency 44100 Hz", "btavdtp.codec.sbc.sampling_frequency.44100",
FT_BOOLEAN, 8, NULL, 0x02,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg12_sampling_frequency_48000,
{ "Sampling Frequency 48000 Hz", "btavdtp.codec.sbc.sampling_frequency.48000",
FT_BOOLEAN, 8, NULL, 0x01,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg12_vbr_supported,
{ "VBR Supported", "btavdtp.codec.mpeg12.vbr",
FT_BOOLEAN, 16, NULL, 0x8000,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg12_bit_rate,
{ "Bit Rate", "btavdtp.codec.mpeg12.bit_rate",
FT_UINT16, BASE_HEX, NULL, 0x7FFF,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg24_object_type_mpeg2_aac_lc,
{ "MPEG2 ACC LC", "btavdtp.codec.mpeg24.object_type.mpeg2_aac_lc",
FT_UINT8, BASE_HEX, NULL, 0x80,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg24_object_type_mpeg4_aac_lc,
{ "MPEG4 ACC LC", "btavdtp.codec.mpeg24.object_type.mpeg4_aac_lc",
FT_UINT8, BASE_HEX, NULL, 0x40,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg24_object_type_mpeg4_aac_ltp,
{ "MPEG4 ACC LTP", "btavdtp.codec.mpeg24.object_type.mpeg4_aac_ltp",
FT_UINT8, BASE_HEX, NULL, 0x20,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg24_object_type_mpeg4_aac_scalable,
{ "MPEG4 ACC Scalable", "btavdtp.codec.mpeg24.object_type.mpeg4_aac_scalable",
FT_UINT8, BASE_HEX, NULL, 0x10,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg24_object_type_rfa,
{ "RFA", "btavdtp.codec.mpeg24.object_type.rfa",
FT_UINT8, BASE_HEX, NULL, 0x0F,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg24_sampling_frequency_8000,
{ "Sampling Frequency 8000 Hz", "btavdtp.codec.mpeg24.sampling_frequency.8000",
FT_BOOLEAN, 8, NULL, 0x80,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg24_sampling_frequency_11025,
{ "Sampling Frequency 11025 Hz", "btavdtp.codec.mpeg24.sampling_frequency.11025",
FT_BOOLEAN, 8, NULL, 0x40,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg24_sampling_frequency_12000,
{ "Sampling Frequency 12000 Hz", "btavdtp.codec.mpeg24.sampling_frequency.12000",
FT_BOOLEAN, 8, NULL, 0x20,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg24_sampling_frequency_16000,
{ "Sampling Frequency 16000 Hz", "btavdtp.codec.mpeg24.sampling_frequency.16000",
FT_BOOLEAN, 8, NULL, 0x10,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg24_sampling_frequency_22050,
{ "Sampling Frequency 22050 Hz", "btavdtp.codec.mpeg24.sampling_frequency.22050",
FT_BOOLEAN, 8, NULL, 0x08,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg24_sampling_frequency_24000,
{ "Sampling Frequency 24000 Hz", "btavdtp.codec.mpeg24.sampling_frequency.24000",
FT_BOOLEAN, 8, NULL, 0x04,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg24_sampling_frequency_32000,
{ "Sampling Frequency 32000 Hz", "btavdtp.codec.mpeg24.sampling_frequency.32000",
FT_BOOLEAN, 8, NULL, 0x02,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg24_sampling_frequency_44100,
{ "Sampling Frequency 44100 Hz", "btavdtp.codec.mpeg24.sampling_frequency.44100",
FT_BOOLEAN, 8, NULL, 0x01,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg24_sampling_frequency_48000,
{ "Sampling Frequency 48000 Hz", "btavdtp.codec.mpeg24.sampling_frequency.48000",
FT_BOOLEAN, 8, NULL, 0x80,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg24_sampling_frequency_64000,
{ "Sampling Frequency 64000 Hz", "btavdtp.codec.mpeg24.sampling_frequency.64000",
FT_BOOLEAN, 8, NULL, 0x40,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg24_sampling_frequency_88200,
{ "Sampling Frequency 88200 Hz", "btavdtp.codec.mpeg24.sampling_frequency.88200",
FT_BOOLEAN, 8, NULL, 0x20,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg24_sampling_frequency_96000,
{ "Sampling Frequency 96000 Hz", "btavdtp.codec.mpeg24.sampling_frequency.96000",
FT_BOOLEAN, 8, NULL, 0x10,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg24_channels_1,
{ "Channels 1", "btavdtp.codec.mpeg24.channels.1",
FT_BOOLEAN, 8, NULL, 0x08,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg24_channels_2,
{ "Channels 2", "btavdtp.codec.mpeg24.channels.2",
FT_BOOLEAN, 8, NULL, 0x04,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg24_rfa,
{ "RFA", "btavdtp.codec.mpeg24.rfa",
FT_UINT8, BASE_HEX, NULL, 0x03,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg24_vbr_supported,
{ "VBR Supported", "btavdtp.codec.mpeg24.vbr",
FT_BOOLEAN, 24, NULL, 0x800000,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg24_bit_rate,
{ "Bit Rate", "btavdtp.codec.mpeg24.bit_rate",
FT_UINT24, BASE_HEX, NULL, 0x7FFFFF,
NULL, HFILL }
},
{ &hf_btavdtp_atrac_version,
{ "Version", "btavdtp.codec.atrac.version",
FT_UINT8, BASE_DEC, NULL, 0xE0,
NULL, HFILL }
},
{ &hf_btavdtp_atrac_channel_mode_single_channel,
{ "Channel Mode Single Channel", "btavdtp.codec.atrac.channel_mode.single_channel",
FT_BOOLEAN, 8, NULL, 0x10,
NULL, HFILL }
},
{ &hf_btavdtp_atrac_channel_mode_dual_channel,
{ "Channel Mode Dual Channel", "btavdtp.codec.atrac.channel_mode.dual_channel",
FT_BOOLEAN, 8, NULL, 0x08,
NULL, HFILL }
},
{ &hf_btavdtp_atrac_channel_mode_joint_stereo,
{ "Channel Mode Joint Stereo", "btavdtp.codec.atrac.channel_mode.joint_stereo",
FT_BOOLEAN, 8, NULL, 0x04,
NULL, HFILL }
},
{ &hf_btavdtp_atrac_rfa1,
{ "RFA", "btavdtp.codec.atrac.rfa1",
FT_UINT8, BASE_HEX, NULL, 0x03,
NULL, HFILL }
},
{ &hf_btavdtp_atrac_rfa2,
{ "RFA", "btavdtp.codec.atrac.rfa2",
FT_UINT24, BASE_HEX, NULL, 0xC00000,
NULL, HFILL }
},
{ &hf_btavdtp_atrac_sampling_frequency_44100,
{ "Sampling Frequency 44100 Hz", "btavdtp.codec.sbc.sampling_frequency.44100",
FT_BOOLEAN, 24, NULL, 0x200000,
NULL, HFILL }
},
{ &hf_btavdtp_atrac_sampling_frequency_48000,
{ "Sampling Frequency 48000 Hz", "btavdtp.codec.sbc.sampling_frequency.48000",
FT_BOOLEAN, 24, NULL, 0x100000,
NULL, HFILL }
},
{ &hf_btavdtp_atrac_vbr_supported,
{ "VBR Supported", "btavdtp.codec.atrac.vbr",
FT_BOOLEAN, 24, NULL, 0x080000,
NULL, HFILL }
},
{ &hf_btavdtp_atrac_bit_rate,
{ "Bit Rate", "btavdtp.codec.atrac.bit_rate",
FT_UINT24, BASE_HEX, NULL, 0x07FFFF,
NULL, HFILL }
},
{ &hf_btavdtp_atrac_maximum_sul,
{ "Maximum SUL", "btavdtp.codec.atrac.maximum_sul",
FT_UINT8, BASE_DEC, NULL, 0x00,
"Sound Unit Length (SUL) is one of the parameters that determine bit rate of the audio stream.", HFILL }
},
{ &hf_btavdtp_atrac_rfa3,
{ "RFA", "btavdtp.codec.atrac.rfa3",
FT_UINT8, BASE_HEX, NULL, 0x00,
NULL, HFILL }
},
{ &hf_btavdtp_h263_level_10,
{ "H264 Level 10", "btavdtp.codec.h264.level.10",
FT_BOOLEAN, 8, NULL, 0x80,
NULL, HFILL }
},
{ &hf_btavdtp_h263_level_20,
{ "H264 Level 20", "btavdtp.codec.h264.level.20",
FT_BOOLEAN, 8, NULL, 0x40,
NULL, HFILL }
},
{ &hf_btavdtp_h263_level_30,
{ "H264 Level 30", "btavdtp.codec.h264.level.30",
FT_BOOLEAN, 8, NULL, 0x20,
NULL, HFILL }
},
{ &hf_btavdtp_h263_level_rfa,
{ "H264 Level RFA", "btavdtp.codec.h264.level.rfa",
FT_UINT8, BASE_HEX, NULL, 0x1F,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg4_level_0,
{ "MPEG Level 0", "btavdtp.codec.mpeg4.level.0",
FT_BOOLEAN, 8, NULL, 0x80,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg4_level_1,
{ "MPEG Level 1", "btavdtp.codec.mpeg4.level.1",
FT_BOOLEAN, 8, NULL, 0x40,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg4_level_2,
{ "MPEG Level 2", "btavdtp.codec.mpeg4.level.2",
FT_BOOLEAN, 8, NULL, 0x20,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg4_level_3,
{ "MPEG4 Level 3", "btavdtp.codec.mpeg4.level.3",
FT_BOOLEAN, 8, NULL, 0x10,
NULL, HFILL }
},
{ &hf_btavdtp_mpeg4_level_rfa,
{ "MPEG4 Level RFA", "btavdtp.codec.mpeg4.level.rfa",
FT_UINT8, BASE_HEX, NULL, 0x0F,
NULL, HFILL }
},
{ &hf_btavdtp_vendor_id,
{ "Vendor ID", "btavdtp.codec.vendor.vendor_id",
FT_UINT32, BASE_HEX|BASE_EXT_STRING, &bthci_evt_comp_id_ext, 0x00,
NULL, HFILL }
},
{ &hf_btavdtp_vendor_specific_codec_id,
{ "Codec", "btavdtp.codec.vendor.codec_id",
FT_UINT16, BASE_HEX, NULL, 0x00,
NULL, HFILL }
},
{ &hf_btavdtp_vendor_specific_value,
{ "Value", "btavdtp.codec.vendor.value",
FT_NONE, BASE_NONE, NULL, 0x00,
NULL, HFILL }
},
{ &hf_btavdtp_capabilities,
{ "Capabilities", "btavdtp.capabilities",
FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_btavdtp_service,
{ "Service", "btavdtp.service",
FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_btavdtp_service_multiplexing_entry,
{ "Entry", "btavdtp.service_multiplexing_entry",
FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_btavdtp_data,
{ "Data", "btavdtp.data",
FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL }
}
};
static gint *ett[] = {
&ett_btavdtp,
&ett_btavdtp_sep,
&ett_btavdtp_capabilities,
&ett_btavdtp_service,
};
proto_btavdtp = proto_register_protocol("Bluetooth AVDTP Protocol", "BT AVDTP", "btavdtp");
new_register_dissector("btavdtp", dissect_btavdtp, proto_btavdtp);
proto_register_field_array(proto_btavdtp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
module = prefs_register_protocol(proto_btavdtp, NULL);
prefs_register_static_text_preference(module, "avdtp.version",
"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 */
}
void
proto_reg_handoff_btavdtp(void)
{
btavdtp_handle = find_dissector("btavdtp");
bta2dp_handle = find_dissector("bta2dp");
btvdp_handle = find_dissector("btvdp");
dissector_add_uint("btl2cap.service", BTSDP_AVDTP_PROTOCOL_UUID, btavdtp_handle);
dissector_add_uint("btl2cap.psm", BTL2CAP_PSM_AVDTP, btavdtp_handle);
dissector_add_handle("btl2cap.cid", btavdtp_handle);
}
static gint
dissect_bta2dp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
{
proto_item *ti;
proto_tree *bta2dp_tree;
proto_item *pitem;
gint offset = 0;
dissector_handle_t codec_dissector = NULL;
bta2dp_codec_info_t bta2dp_codec_info;
sep_data_t sep_data;
sep_data.codec = CODEC_SBC;
sep_data.content_protection_type = 0;
if (force_a2dp_scms_t || force_a2dp_codec) {
if (force_a2dp_scms_t)
sep_data.content_protection_type = 2;
else if (data)
sep_data.content_protection_type = ((sep_data_t *) data)->content_protection_type;
if (force_a2dp_codec)
sep_data.codec = force_a2dp_codec;
else if (data)
sep_data.codec = ((sep_data_t *) data)->codec;
} else {
if (data)
sep_data = *((sep_data_t *) data);
}
col_set_str(pinfo->cinfo, COL_PROTOCOL, "A2DP");
switch (pinfo->p2p_dir) {
case P2P_DIR_SENT:
col_set_str(pinfo->cinfo, COL_INFO, "Sent ");
break;
case P2P_DIR_RECV:
col_set_str(pinfo->cinfo, COL_INFO, "Rcvd ");
break;
case P2P_DIR_UNKNOWN:
col_clear(pinfo->cinfo, COL_INFO);
break;
default:
col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown direction %d ",
pinfo->p2p_dir);
break;
}
ti = proto_tree_add_item(tree, proto_bta2dp, tvb, offset, -1, ENC_NA);
col_append_fstr(pinfo->cinfo, COL_INFO, "Audio stream - %s",
val_to_str_const(sep_data.codec, media_codec_audio_type_vals, "unknown codec"));
bta2dp_tree = proto_item_add_subtree(ti, ett_bta2dp);
pitem = proto_tree_add_uint(bta2dp_tree, hf_bta2dp_codec, tvb, offset, 0, sep_data.codec);
PROTO_ITEM_SET_GENERATED(pitem);
if (sep_data.content_protection_type > 0) {
pitem = proto_tree_add_uint(bta2dp_tree, hf_bta2dp_content_protection, tvb, offset, 0, sep_data.content_protection_type);
PROTO_ITEM_SET_GENERATED(pitem);
}
switch (sep_data.codec) {
case CODEC_SBC:
codec_dissector = sbc_handle;
break;
case CODEC_MPEG12_AUDIO:
codec_dissector = mp2t_handle;
break;
case CODEC_MPEG24_AAC:
codec_dissector = mpeg_audio_handle;
break;
case CODEC_ATRAC:
codec_dissector = atrac_handle;
break;
}
bta2dp_codec_info.codec_dissector = codec_dissector;
bta2dp_codec_info.content_protection_type = sep_data.content_protection_type;
bluetooth_add_address(pinfo, &pinfo->net_dst, "BT A2DP", pinfo->fd->num, FALSE, &bta2dp_codec_info);
call_dissector(rtp_handle, tvb, pinfo, tree);
offset += tvb_length_remaining(tvb, offset);
return offset;
}
void
proto_register_bta2dp(void)
{
module_t *module;
static hf_register_info hf[] = {
{ &hf_bta2dp_codec,
{ "Codec", "bta2dp.codec",
FT_UINT8, BASE_HEX, VALS(media_codec_audio_type_vals), 0x00,
NULL, HFILL }
},
{ &hf_bta2dp_content_protection,
{ "Content Protection", "bta2dp.content_protection",
FT_UINT16, BASE_HEX, VALS(content_protection_type_vals), 0x0000,
NULL, HFILL }
}
};
static gint *ett[] = {
&ett_bta2dp
};
proto_bta2dp = proto_register_protocol("Bluetooth A2DP Profile", "BT A2DP", "bta2dp");
proto_register_field_array(proto_bta2dp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
new_register_dissector("bta2dp", dissect_bta2dp, proto_bta2dp);
module = prefs_register_protocol(proto_bta2dp, NULL);
prefs_register_static_text_preference(module, "a2dp.version",
"Bluetooth Profile A2DP version: 1.3",
"Version of profile supported by this dissector.");
prefs_register_bool_preference(module, "a2dp.content_protection.scms_t",
"Force SCMS-T decoding",
"Force decoding stream as A2DP with Content Protection SCMS-T ",
&force_a2dp_scms_t);
prefs_register_enum_preference(module, "a2dp.codec",
"Force codec",
"Force decoding stream as A2DP with specified codec",
&force_a2dp_codec, pref_a2dp_codec, FALSE);
}
void
proto_reg_handoff_bta2dp(void)
{
sbc_handle = find_dissector("sbc");
mp2t_handle = find_dissector("mp2t");
mpeg_audio_handle = find_dissector("mpeg-audio");
/* TODO: ATRAC dissector does not exist yet */
atrac_handle = find_dissector("atrac");
bta2dp_handle = find_dissector("bta2dp");
rtp_handle = find_dissector("rtp");
dissector_add_uint("btl2cap.service", BTSDP_A2DP_SOURCE_SERVICE_UUID, bta2dp_handle);
dissector_add_uint("btl2cap.service", BTSDP_A2DP_SINK_SERVICE_UUID, bta2dp_handle);
dissector_add_uint("btl2cap.service", BTSDP_A2DP_DISTRIBUTION_SERVICE_UUID, bta2dp_handle);
dissector_add_handle("btl2cap.cid", bta2dp_handle);
}
static gint
dissect_btvdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
{
proto_item *ti;
proto_tree *btvdp_tree;
proto_item *pitem;
gint offset = 0;
dissector_handle_t codec_dissector = NULL;
btvdp_codec_info_t btvdp_codec_info;
sep_data_t sep_data;
sep_data.codec = CODEC_H263_BASELINE;
sep_data.content_protection_type = 0;
if (force_vdp_scms_t || force_vdp_codec) {
if (force_vdp_scms_t)
sep_data.content_protection_type = 2;
else if (data)
sep_data.content_protection_type = ((sep_data_t *) data)->content_protection_type;
if (force_vdp_codec)
sep_data.codec = force_vdp_codec;
else if (data)
sep_data.codec = ((sep_data_t *) data)->codec;
} else {
if (data)
sep_data = *((sep_data_t *) data);
}
col_set_str(pinfo->cinfo, COL_PROTOCOL, "VDP");
switch (pinfo->p2p_dir) {
case P2P_DIR_SENT:
col_set_str(pinfo->cinfo, COL_INFO, "Sent ");
break;
case P2P_DIR_RECV:
col_set_str(pinfo->cinfo, COL_INFO, "Rcvd ");
break;
case P2P_DIR_UNKNOWN:
col_clear(pinfo->cinfo, COL_INFO);
break;
default:
col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown direction %d ",
pinfo->p2p_dir);
break;
}
ti = proto_tree_add_item(tree, proto_btvdp, tvb, offset, -1, ENC_NA);
col_append_fstr(pinfo->cinfo, COL_INFO, "Video stream - %s",
val_to_str_const(sep_data.codec, media_codec_video_type_vals, "unknown codec"));
btvdp_tree = proto_item_add_subtree(ti, ett_btvdp);
pitem = proto_tree_add_uint(btvdp_tree, hf_btvdp_codec, tvb, offset, 0, sep_data.codec);
PROTO_ITEM_SET_GENERATED(pitem);
if (sep_data.content_protection_type > 0) {
pitem = proto_tree_add_uint(btvdp_tree, hf_btvdp_content_protection, tvb, offset, 0, sep_data.content_protection_type);
PROTO_ITEM_SET_GENERATED(pitem);
}
switch (sep_data.codec) {
case CODEC_H263_BASELINE:
case CODEC_H263_PROFILE_3:
case CODEC_H263_PROFILE_8:
codec_dissector = h263_handle;
break;
case CODEC_MPEG4_VSP:
codec_dissector = mp4v_es_handle;
break;
}
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);
call_dissector(rtp_handle, tvb, pinfo, tree);
offset += tvb_length_remaining(tvb, offset);
return offset;
}
void
proto_register_btvdp(void)
{
module_t *module;
expert_module_t* expert_btavdtp;
static hf_register_info hf[] = {
{ &hf_btvdp_codec,
{ "Codec", "btvdp.codec",
FT_UINT8, BASE_HEX, VALS(media_codec_video_type_vals), 0x00,
NULL, HFILL }
},
{ &hf_btvdp_content_protection,
{ "Content Protection", "btvdp.content_protection",
FT_UINT16, BASE_HEX, VALS(content_protection_type_vals), 0x0000,
NULL, HFILL }
}
};
static gint *ett[] = {
&ett_btvdp
};
static ei_register_info ei[] = {
{ &ei_btavdtp_sbc_min_bitpool_out_of_range, { "btavdtp.codec.sbc.minimum_bitpool.out_of_range", PI_PROTOCOL, PI_WARN, "Bitpool is out of range. Should be 2..250.", EXPFILL }},
{ &ei_btavdtp_sbc_max_bitpool_out_of_range, { "btavdtp.codec.sbc.maximum_bitpool.out_of_range", PI_PROTOCOL, PI_WARN, "Bitpool is out of range. Should be 2..250.", EXPFILL }},
{ &ei_btavdtp_unexpected_losc_data, { "btavdtp.unexpected_losc_data", PI_PROTOCOL, PI_WARN, "Unexpected losc data", EXPFILL }},
};
proto_btvdp = proto_register_protocol("Bluetooth VDP Profile", "BT VDP", "btvdp");
new_register_dissector("btvdp", dissect_btvdp, proto_btvdp);
proto_register_field_array(proto_bta2dp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
expert_btavdtp = expert_register_protocol(proto_btvdp);
expert_register_field_array(expert_btavdtp, ei, array_length(ei));
module = prefs_register_protocol(proto_btvdp, NULL);
prefs_register_static_text_preference(module, "vdp.version",
"Bluetooth Profile VDP version: 1.1",
"Version of profile supported by this dissector.");
prefs_register_bool_preference(module, "vdp.content_protection.scms_t",
"Force SCMS-T decoding",
"Force decoding stream as VDP with Content Protection SCMS-T ",
&force_vdp_scms_t);
prefs_register_enum_preference(module, "vdp.codec",
"Force codec",
"Force decoding stream as VDP with specified codec",
&force_vdp_codec, pref_vdp_codec, FALSE);
}
void
proto_reg_handoff_btvdp(void)
{
h263_handle = find_dissector("h263");
mp4v_es_handle = find_dissector("mp4v-es");
rtp_handle = find_dissector("rtp");
btvdp_handle = find_dissector("btvdp");
dissector_add_uint("btl2cap.service", BTSDP_VDP_SOURCE_SERVICE_UUID, btvdp_handle);
dissector_add_uint("btl2cap.service", BTSDP_VDP_SINK_SERVICE_UUID, btvdp_handle);
dissector_add_uint("btl2cap.service", BTSDP_VDP_DISTRIBUTION_SERVICE_UUID, btvdp_handle);
dissector_add_handle("btl2cap.cid", btvdp_handle);
}
static gint
dissect_a2dp_cp_scms_t(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
{
proto_item *main_item;
proto_tree *main_tree;
gint offset = 0;
main_item = proto_tree_add_item(tree, proto_bta2dp_cph_scms_t, tvb, offset, 1, ENC_NA);
main_tree = proto_item_add_subtree(main_item, ett_bta2dp_cph_scms_t);
proto_tree_add_item(main_tree, hf_bta2dp_reserved , tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(main_tree, hf_bta2dp_cp_bit, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(main_tree, hf_bta2dp_l_bit , tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
return offset;
}
void
proto_register_bta2dp_content_protection_header_scms_t(void)
{
static hf_register_info hf[] = {
{ &hf_bta2dp_l_bit,
{ "L-bit", "bta2dp.content_protection_header.scms_t.l_bit",
FT_BOOLEAN, 8, NULL, 0x01,
NULL, HFILL }
},
{ &hf_bta2dp_cp_bit,
{ "Cp-bit", "bta2dp.content_protection_header.scms_t.cp_bit",
FT_BOOLEAN, 8, NULL, 0x02,
NULL, HFILL }
},
{ &hf_bta2dp_reserved,
{ "Reserved", "bta2dp.content_protection_header.scms_t.reserved",
FT_BOOLEAN, 8, NULL, 0xFC,
NULL, HFILL }
}
};
static gint *ett[] = {
&ett_bta2dp_cph_scms_t
};
proto_bta2dp_cph_scms_t = proto_register_protocol("Bluetooth A2DP Content Protection Header SCMS-T", "BT A2DP Content Protection Header SCMS-T", "bta2dp_content_protection_header_scms_t");
proto_register_field_array(proto_bta2dp_cph_scms_t, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
new_register_dissector("bta2dp_content_protection_header_scms_t", dissect_a2dp_cp_scms_t, proto_bta2dp_cph_scms_t);
}
static gint
dissect_vdp_cp_scms_t(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
{
proto_item *main_item;
proto_tree *main_tree;
gint offset = 0;
main_item = proto_tree_add_item(tree, proto_btvdp_cph_scms_t, tvb, offset, 1, ENC_NA);
main_tree = proto_item_add_subtree(main_item, ett_btvdp_cph_scms_t);
proto_tree_add_item(main_tree, hf_btvdp_reserved , tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(main_tree, hf_btvdp_cp_bit, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(main_tree, hf_btvdp_l_bit , tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
return offset;
}
void
proto_register_btvdp_content_protection_header_scms_t(void)
{
static hf_register_info hf[] = {
{ &hf_btvdp_l_bit,
{ "L-bit", "btvdp.content_protection_header.scms_t.l_bit",
FT_BOOLEAN, 8, NULL, 0x01,
NULL, HFILL }
},
{ &hf_btvdp_cp_bit,
{ "Cp-bit", "btvdp.content_protection_header.scms_t.cp_bit",
FT_BOOLEAN, 8, NULL, 0x02,
NULL, HFILL }
},
{ &hf_btvdp_reserved,
{ "Reserved", "btvdp.content_protection_header.scms_t.reserved",
FT_BOOLEAN, 8, NULL, 0xFC,
NULL, HFILL }
}
};
static gint *ett[] = {
&ett_btvdp_cph_scms_t
};
proto_btvdp_cph_scms_t = proto_register_protocol("Bluetooth VDP Content Protection Header SCMS-T", "BT VDP Content Protection Header SCMS-T", "btvdp_content_protection_header_scms_t");
proto_register_field_array(proto_btvdp_cph_scms_t, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
new_register_dissector("btvdp_content_protection_header_scms_t", dissect_vdp_cp_scms_t, proto_btvdp_cph_scms_t);
}
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/