diff options
author | Jakub Pawlowski <jpawlowski@google.com> | 2018-12-27 12:46:00 +0100 |
---|---|---|
committer | Anders Broman <a.broman58@gmail.com> | 2019-02-20 06:09:39 +0000 |
commit | 8b0e851d4ed93cc4ea91d3d025faa9d329404369 (patch) | |
tree | 5b2fecd9bfd4df3dbb1518011395b78166ab8bdc /epan | |
parent | fc0e5d48d5db9f613b52c035cc8c99905d2000b0 (diff) |
Bluetooth: LDAC dissector
Change-Id: I22baf475b3d11dd23fae4c917b27c7aaa13654b4
Reviewed-on: https://code.wireshark.org/review/31799
Petri-Dish: Anders Broman <a.broman58@gmail.com>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
Diffstat (limited to 'epan')
-rw-r--r-- | epan/dissectors/packet-btavdtp.c | 357 | ||||
-rw-r--r-- | epan/dissectors/packet-btl2cap.c | 13 |
2 files changed, 336 insertions, 34 deletions
diff --git a/epan/dissectors/packet-btavdtp.c b/epan/dissectors/packet-btavdtp.c index 179ba239bf..b6c5e630c9 100644 --- a/epan/dissectors/packet-btavdtp.c +++ b/epan/dissectors/packet-btavdtp.c @@ -277,6 +277,7 @@ 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_vendor_specific_apt_codec_id = -1; +static int hf_btavdtp_vendor_specific_ldac_codec_id = -1; static int hf_btavdtp_capabilities = -1; static int hf_btavdtp_service = -1; static int hf_btavdtp_service_multiplexing_entry = -1; @@ -335,7 +336,7 @@ static const enum_val_t pref_a2dp_codec[] = { /* XXX: Not supported in Wireshark yet { "atrac", "ATRAC", CODEC_ATRAC },*/ { "aptx", "aptX", CODEC_APT_X }, { "aptx-hd", "aptX HD", CODEC_APT_X_HD }, -/* XXX: Not supported in Wireshark yet { "ldac", "LDAC", CODEC_LDAC },*/ + { "ldac", "LDAC", CODEC_LDAC }, { NULL, NULL, 0 } }; @@ -383,6 +384,56 @@ static int hf_aptx_diff = -1; static gint ett_aptx = -1; static dissector_handle_t aptx_handle; +/* LDAC Codec */ +static int proto_ldac = -1; +static int hf_ldac_fragmented = -1; +static int hf_ldac_starting_packet = -1; +static int hf_ldac_last_packet = -1; +static int hf_ldac_rfa = -1; +static int hf_ldac_number_of_frames = -1; + +static int hf_ldac_syncword = -1; +static int hf_ldac_sampling_frequency = -1; +static int hf_ldac_channel_config_index = -1; +static int hf_ldac_frame_length_h = -1; +static int hf_ldac_frame_length_l = -1; +static int hf_ldac_frame_status = -1; + +static int hf_ldac_expected_data_speed = -1; + +static int hf_ldac_data = -1; +static gint ett_ldac = -1; +static gint ett_ldac_list = -1; +static expert_field ei_ldac_syncword = EI_INIT; +static expert_field ei_ldac_truncated_or_bad_length = EI_INIT; +static dissector_handle_t ldac_handle; +#define LDAC_CCI_MONO 0x0 +#define LDAC_CCI_DUAL 0x1 +#define LDAC_CCI_STEREO 0x2 +static const value_string ldac_channel_config_index_vals[] = { + { LDAC_CCI_MONO, "Mono"}, + { LDAC_CCI_DUAL, "Dual Channel"}, + { LDAC_CCI_STEREO, "Stereo"}, + { 0, NULL } +}; + +#define LDAC_FSID_044 0x0 +#define LDAC_FSID_048 0x1 +#define LDAC_FSID_088 0x2 +#define LDAC_FSID_096 0x3 +#define LDAC_FSID_176 0x4 +#define LDAC_FSID_192 0x5 + +static const value_string ldac_sampling_frequency_vals[] = { + { LDAC_FSID_044, "44.1 kHz"}, + { LDAC_FSID_048, "48.0 kHz"}, + { LDAC_FSID_088, "88.2 kHz"}, + { LDAC_FSID_096, "96.0 kHz"}, + { LDAC_FSID_176, "176.4 kHz"}, + { LDAC_FSID_192, "192.0 kHz"}, + { 0, NULL } +}; + static const value_string message_type_vals[] = { { 0x00, "Command" }, @@ -556,6 +607,10 @@ static const value_string content_protection_type_vals[] = { static const value_string vendor_apt_codec_vals[] = { { CODECID_APT_X, "aptX" }, { CODECID_APT_X_HD, "aptX HD" }, + { 0, NULL } +}; + +static const value_string vendor_ldac_codec_vals[] = { { 0x00AA, "LDAC" }, { 0, NULL } }; @@ -626,6 +681,7 @@ void proto_register_btvdp(void); void proto_reg_handoff_btvdp(void); void proto_register_btvdp_content_protection_header_scms_t(void); void proto_register_aptx(void); +void proto_register_ldac(void); static const char * @@ -1011,10 +1067,12 @@ dissect_codec(tvbuff_t *tvb, packet_info *pinfo, proto_item *service_item, proto proto_tree_add_item(tree, hf_btavdtp_vendor_specific_value, tvb, offset + 6, losc - 6, ENC_NA); } break; - case 0x012D: /* Sony Corporation */ - proto_tree_add_item(tree, hf_btavdtp_vendor_specific_apt_codec_id, tvb, offset + 4, 2, ENC_LITTLE_ENDIAN); + case 0x012D: /* Sony Corporation. */ + proto_tree_add_item(tree, hf_btavdtp_vendor_specific_ldac_codec_id, tvb, offset + 4, 2, ENC_LITTLE_ENDIAN); value = tvb_get_letohs(tvb, offset + 4); + if (value == 0x00AA) { /* LDAC Codec */ + int value2; proto_tree_add_item(tree, hf_btavdtp_vendor_specific_ldac_rfa1, tvb, offset + 6, 1, ENC_NA); proto_tree_add_item(tree, hf_btavdtp_vendor_specific_ldac_sampling_frequency_44100, tvb, offset + 6, 1, ENC_NA); proto_tree_add_item(tree, hf_btavdtp_vendor_specific_ldac_sampling_frequency_48000, tvb, offset + 6, 1, ENC_NA); @@ -1028,37 +1086,34 @@ dissect_codec(tvbuff_t *tvb, packet_info *pinfo, proto_item *service_item, proto proto_tree_add_item(tree, hf_btavdtp_vendor_specific_ldac_channel_mode_stereo, tvb, offset + 7, 1, ENC_NA); col_append_fstr(pinfo->cinfo, COL_INFO, " (%s -", - val_to_str_const(value, vendor_apt_codec_vals, "unknown codec")); + val_to_str_const(value, vendor_ldac_codec_vals, "unknown codec")); proto_item_append_text(service_item, " (%s -", - val_to_str_const(value, vendor_apt_codec_vals, "unknown codec")); + val_to_str_const(value, vendor_ldac_codec_vals, "unknown codec")); - value = tvb_get_letohs(tvb, offset + 6); - if (value) { - col_append_fstr(pinfo->cinfo, COL_INFO, "%s%s%s%s%s%s%s,%s%s%s%s)", - (value & 0x0020) ? " 44100" : "", - (value & 0x0010) ? " 48000" : "", - (value & 0x0008) ? " 88200" : "", - (value & 0x0004) ? " 96000" : "", - (value & 0x0002) ? " 176400" : "", - (value & 0x0001) ? " 192000" : "", - (value & 0x003F) ? "" : "not set ", - (value & 0x0400) ? " Mono" : "", - (value & 0x0200) ? " DualChannel" : "", - (value & 0x0100) ? " Stereo" : "", - (value & 0x0700) ? "" : "not set "); - - proto_item_append_text(service_item, "%s%s%s%s%s%s%s,%s%s%s%s)", - (value & 0x0020) ? " 44100" : "", - (value & 0x0010) ? " 48000" : "", - (value & 0x0008) ? " 88200" : "", - (value & 0x0004) ? " 96000" : "", - (value & 0x0002) ? " 176400" : "", - (value & 0x0001) ? " 192000" : "", - (value & 0x003F) ? "" : "not set ", - (value & 0x0400) ? " Mono" : "", - (value & 0x0200) ? " DualChannel" : "", - (value & 0x0100) ? " Stereo" : "", - (value & 0x0700) ? "" : "not set "); + value = tvb_get_guint8(tvb, offset + 6); + value2 = tvb_get_guint8(tvb, offset + 7); + if (value != 0 && value2 != 0) { + col_append_fstr(pinfo->cinfo, COL_INFO, "%s%s%s%s%s%s,%s%s%s)", + (value & 0x20) ? " 44100" : "", + (value & 0x10) ? " 48000" : "", + (value & 0x08) ? " 88200" : "", + (value & 0x04) ? " 96000" : "", + (value & 0x02) ? "176400" : "", + (value & 0x01) ? "192000" : "", + (value2 & 0x04) ? " Mono" : "", + (value2 & 0x02) ? " DualChannel" : "", + (value2 & 0x01) ? " Stereo" : ""); + + proto_item_append_text(service_item, "%s%s%s%s%s%s,%s%s%s)", + (value & 0x20) ? " 44100" : "", + (value & 0x10) ? " 48000" : "", + (value & 0x08) ? " 88200" : "", + (value & 0x04) ? " 96000" : "", + (value & 0x02) ? "176400" : "", + (value & 0x01) ? "192000" : "", + (value2 & 0x04) ? " Mono" : "", + (value2 & 0x02) ? " DualChannel" : "", + (value2 & 0x01) ? " Stereo" : ""); } else { col_append_fstr(pinfo->cinfo, COL_INFO, " none)"); proto_item_append_text(service_item, " none)"); @@ -2827,6 +2882,11 @@ proto_register_btavdtp(void) FT_UINT8, BASE_HEX, NULL, 0xC0, NULL, HFILL } }, + { &hf_btavdtp_vendor_specific_ldac_codec_id, + { "Codec", "btavdtp.codec.vendor.codec_id", + FT_UINT16, BASE_HEX, VALS(vendor_ldac_codec_vals), 0x00, + NULL, HFILL } + }, { &hf_btavdtp_vendor_specific_ldac_sampling_frequency_44100, { "Sampling Frequency 44100 Hz", "btavdtp.codec.ldac.sampling_frequency.44100", FT_BOOLEAN, 8, NULL, 0x20, @@ -3112,6 +3172,233 @@ proto_register_aptx(void) aptx_handle = register_dissector("aptx", dissect_aptx, proto_aptx); } +static gint +dissect_ldac(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) +{ + proto_item *ti; + proto_tree *ldac_tree; + proto_item *pitem; + proto_tree *rtree; + gint offset = 0; + guint8 number_of_frames; + guint8 syncword; + guint8 byte; + guint8 cci; + guint frequency; + gint available; + gint ldac_channels; + gint counter = 1; + gint frame_length; + gint frame_sample_size; + gint expected_speed_data; + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "LDAC"); + + ti = proto_tree_add_item(tree, proto_ldac, tvb, offset, -1, ENC_NA); + ldac_tree = proto_item_add_subtree(ti, ett_ldac); + + proto_tree_add_item(ldac_tree, hf_ldac_fragmented, tvb, offset, 1, ENC_BIG_ENDIAN); + proto_tree_add_item(ldac_tree, hf_ldac_starting_packet, tvb, offset, 1, ENC_BIG_ENDIAN); + proto_tree_add_item(ldac_tree, hf_ldac_last_packet, tvb, offset, 1, ENC_BIG_ENDIAN); + proto_tree_add_item(ldac_tree, hf_ldac_rfa, tvb, offset, 1, ENC_BIG_ENDIAN); + proto_tree_add_item(ldac_tree, hf_ldac_number_of_frames, tvb, offset, 1, ENC_BIG_ENDIAN); + number_of_frames = tvb_get_guint8(tvb, offset) & 0x0F; + offset += 1; + + while (tvb_reported_length_remaining(tvb, offset) > 0) { + available = tvb_reported_length_remaining(tvb, offset); + + syncword = tvb_get_guint8(tvb, offset); + if (syncword != 0xAA) { + rtree = proto_tree_add_subtree_format(ldac_tree, tvb, offset, 1, + ett_ldac_list, NULL, "Frame: %3u/%3u", counter, number_of_frames); + pitem = proto_tree_add_item(rtree, hf_ldac_syncword, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + expert_add_info(pinfo, pitem, &ei_ldac_syncword); + break; + } + + if (available > 1) { + byte = tvb_get_guint8(tvb, offset + 1); + frequency = (byte & 0xE0) >> 5; + cci = (byte & 0x18)>> 3; + frame_length = byte & 0x07; + frame_length <<= 6; + } else { + frequency = 0; + cci = 0; + } + + if (available > 2) { + byte = tvb_get_guint8(tvb, offset + 2); + frame_length |= (byte & 0xFC) >> 2; + frame_length +=1; + } else { + frame_length = 0; + } + + rtree = proto_tree_add_subtree_format(ldac_tree, tvb, offset, + 3 + frame_length > available ? available : 3 + frame_length, + ett_ldac_list, NULL, "Frame: %3u/%3u", counter, number_of_frames); + + if (3 + frame_length > available) { + expert_add_info(pinfo, rtree, &ei_ldac_truncated_or_bad_length); + } + + pitem = proto_tree_add_item(rtree, hf_ldac_syncword, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + + if (cci == LDAC_CCI_MONO) + ldac_channels = 1; + else + ldac_channels = 2; + + switch (frequency) { + case LDAC_FSID_044: + frequency = 44100; + frame_sample_size = 128; + break; + case LDAC_FSID_048: + frequency = 48000; + frame_sample_size = 128; + break; + case LDAC_FSID_088: + frequency = 88200; + frame_sample_size = 256; + break; + case LDAC_FSID_096: + frequency = 96000; + frame_sample_size = 256; + break; + case LDAC_FSID_176: + frequency = 176400; + frame_sample_size = 512; + break; + case LDAC_FSID_192: + frequency = 192000; + frame_sample_size = 512; + break; + default: + frequency = 0; + frame_sample_size = 1; + } + + proto_tree_add_item(rtree, hf_ldac_sampling_frequency, tvb, offset, 1, ENC_BIG_ENDIAN); + pitem = proto_tree_add_item(rtree, hf_ldac_channel_config_index, tvb, offset, 1, ENC_BIG_ENDIAN); + proto_item_append_text(pitem, ", Number of channels : %d", ldac_channels); + proto_tree_add_item(rtree, hf_ldac_frame_length_h, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(rtree, hf_ldac_frame_length_l, tvb, offset, 1, ENC_BIG_ENDIAN); + proto_tree_add_item(rtree, hf_ldac_frame_status, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + + proto_tree_add_item(rtree, hf_ldac_data, tvb, offset, frame_length, ENC_NA); + offset += frame_length; + + expected_speed_data = (8*(frame_length+3) * frequency) / (frame_sample_size*1000); + pitem = proto_tree_add_uint(rtree, hf_ldac_expected_data_speed, tvb, offset, 0, expected_speed_data); + proto_item_append_text(pitem, " kbits/sec"); + PROTO_ITEM_SET_GENERATED(pitem); + counter += 1; + } + + col_append_fstr(pinfo->cinfo, COL_INFO, " Frames=%u", number_of_frames); + + return offset; +} +void +proto_register_ldac(void) +{ + expert_module_t* expert_ldac; + + static hf_register_info hf[] = { + { &hf_ldac_fragmented, + { "Fragmented", "ldac.fragmented", + FT_BOOLEAN, 8, NULL, 0x80, + NULL, HFILL } + }, + { &hf_ldac_starting_packet, + { "Starting Packet", "ldac.starting_packet", + FT_BOOLEAN, 8, NULL, 0x40, + NULL, HFILL } + }, + { &hf_ldac_last_packet, + { "Last Packet", "ldac.last_packet", + FT_BOOLEAN, 8, NULL, 0x20, + NULL, HFILL } + }, + { &hf_ldac_rfa, + { "RFA", "ldac.rfa", + FT_BOOLEAN, 8, NULL, 0x10, + NULL, HFILL } + }, + { &hf_ldac_number_of_frames, + { "Number of Frames", "ldac.number_of_frames", + FT_UINT8, BASE_DEC, NULL, 0x0F, + NULL, HFILL } + }, + { &hf_ldac_syncword, + { "Sync Word", "ldac.syncword", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ldac_sampling_frequency, + { "Sampling Frequency", "ldac.sampling_frequency", + FT_UINT8, BASE_HEX, VALS(ldac_sampling_frequency_vals), 0xE0, + NULL, HFILL } + }, + { &hf_ldac_channel_config_index, + { "Channel Config Index", "ldac.channel_config_index", + FT_UINT8, BASE_HEX, VALS(ldac_channel_config_index_vals), 0x18, + NULL, HFILL } + }, + { &hf_ldac_frame_length_h, + { "Frame Length Index(H)", "ldac.frame_length_index_H", + FT_UINT8, BASE_HEX, NULL, 0x07, + NULL, HFILL } + }, + { &hf_ldac_frame_length_l, + { "Frame Length Index(L)", "ldac.frame_length_index_L", + FT_UINT8, BASE_HEX, NULL, 0xFC, + NULL, HFILL } + }, + { &hf_ldac_frame_status, + { "Frame Status", "ldac.frame_status", + FT_UINT8, BASE_DEC, NULL, 0x03, + NULL, HFILL } + }, + { &hf_ldac_expected_data_speed, + { "Bitrate", "ldac.expected_speed_data", + FT_UINT32, BASE_DEC, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ldac_data, + { "Frame Data", "ldac.data", + FT_NONE, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + }; + + static gint *ett[] = { + &ett_ldac, + &ett_ldac_list, + }; + + static ei_register_info ei[] = { + { &ei_ldac_syncword, { "ldac.syncword.unexpected", PI_PROTOCOL, PI_WARN, "Unexpected syncword", EXPFILL }}, + { &ei_ldac_truncated_or_bad_length, { "ldac.data.truncated", PI_PROTOCOL, PI_WARN, "Either bad frame length or data truncated", EXPFILL }}, + }; + + proto_ldac = proto_register_protocol("LDAC Codec", "LDAC", "ldac"); + + proto_register_field_array(proto_ldac, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + expert_ldac = expert_register_protocol(proto_ldac); + expert_register_field_array(expert_ldac, ei, array_length(ei)); + + ldac_handle = register_dissector("ldac", dissect_ldac, proto_ldac); + +} static gint dissect_bta2dp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) @@ -3204,6 +3491,9 @@ dissect_bta2dp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) if ((sep_data.vendor_id == 0x004F && sep_data.vendor_codec == CODECID_APT_X) || (sep_data.vendor_id == 0x00D7 && sep_data.vendor_codec == CODECID_APT_X_HD)) codec_dissector = aptx_handle; + + if (sep_data.vendor_id == 0x012D && sep_data.vendor_codec == 0x00AA) + codec_dissector = ldac_handle; } if (sep_data.content_protection_type > 0) { @@ -3241,6 +3531,9 @@ dissect_bta2dp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) case CODEC_APT_X_HD: codec_dissector = aptx_handle; break; + case CODEC_LDAC: + codec_dissector = ldac_handle; + break; } bta2dp_codec_info.codec_dissector = codec_dissector; diff --git a/epan/dissectors/packet-btl2cap.c b/epan/dissectors/packet-btl2cap.c index 04afe3a7a7..d18dd29aba 100644 --- a/epan/dissectors/packet-btl2cap.c +++ b/epan/dissectors/packet-btl2cap.c @@ -1243,7 +1243,7 @@ dissect_configrequest(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree_add_item(tree, hf_btl2cap_flags_continuation, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; - if (tvb_reported_length_remaining(tvb, offset) > 0) { + { psm_data_t *psm_data; config_data_t *config_data; wmem_tree_key_t key[6]; @@ -1300,7 +1300,16 @@ dissect_configrequest(tvbuff_t *tvb, int offset, packet_info *pinfo, } else { config_data = NULL; } - offset = dissect_options(tvb, offset, pinfo, tree, length - 4, config_data); + if (config_data != NULL) { + /* Reset config_data that might have been set by an earlier + * Configure Request that failed. + */ + config_data->mode = L2CAP_BASIC_MODE; + config_data->txwindow = 0; + } + if (tvb_reported_length_remaining(tvb, offset) > 0) { + offset = dissect_options(tvb, offset, pinfo, tree, length - 4, config_data); + } } return offset; |