Coverage Report

Created: 2026-07-12 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-sbc.c
Line
Count
Source
1
/* packet-sbc.c
2
 * Routines for Bluetooth SBC dissection
3
 *
4
 * Copyright 2012, Michal Labedzki for Tieto Corporation
5
 *
6
 * Wireshark - Network traffic analyzer
7
 * By Gerald Combs <gerald@wireshark.org>
8
 * Copyright 1998 Gerald Combs
9
 *
10
 * SPDX-License-Identifier: GPL-2.0-or-later
11
 */
12
13
#include "config.h"
14
15
#include <epan/packet.h>
16
#include <epan/expert.h>
17
#include <epan/prefs.h>
18
#include <epan/unit_strings.h>
19
20
#include <wsutil/array.h>
21
#include "packet-btavdtp.h"
22
23
0
#define CHANNELS_MONO          0x00
24
0
#define CHANNELS_DUAL_CHANNEL  0x01
25
0
#define CHANNELS_JOINT_STEREO  0x03
26
27
0
#define FREQUENCY_16000        0x00
28
0
#define FREQUENCY_32000        0x01
29
0
#define FREQUENCY_44100        0x02
30
0
#define FREQUENCY_48000        0x03
31
32
void proto_register_sbc(void);
33
34
static int proto_sbc;
35
36
static int hf_sbc_fragmented;
37
static int hf_sbc_starting_packet;
38
static int hf_sbc_last_packet;
39
static int hf_sbc_rfa;
40
static int hf_sbc_number_of_frames;
41
42
static int hf_sbc_syncword;
43
static int hf_sbc_sampling_frequency;
44
static int hf_sbc_blocks;
45
static int hf_sbc_channel_mode;
46
static int hf_sbc_allocation_method;
47
static int hf_sbc_subbands;
48
static int hf_sbc_bitpool;
49
static int hf_sbc_crc_check;
50
static int hf_sbc_expected_data_speed;
51
static int hf_sbc_frame_duration;
52
static int hf_sbc_cumulative_frame_duration;
53
static int hf_sbc_delta_time;
54
static int hf_sbc_delta_time_from_the_beginning;
55
static int hf_sbc_cumulative_duration;
56
static int hf_sbc_avrcp_song_position;
57
static int hf_sbc_diff;
58
59
static int hf_sbc_data;
60
61
static int ett_sbc;
62
static int ett_sbc_list;
63
64
static expert_field ei_sbc_syncword;
65
66
static const value_string sampling_frequency_vals[] = {
67
    { 0x00,  "16 kHz"},
68
    { 0x01,  "32 kHz"},
69
    { 0x02,  "44.1 kHz"},
70
    { 0x03,  "48 kHz"},
71
    { 0, NULL }
72
};
73
74
static const value_string blocks_vals[] = {
75
    { 0x00,  "4"},
76
    { 0x01,  "8"},
77
    { 0x02,  "12"},
78
    { 0x03,  "16"},
79
    { 0, NULL }
80
};
81
82
static const value_string channel_mode_vals[] = {
83
    { 0x00,  "Mono"},
84
    { 0x01,  "Dual Channel"},
85
    { 0x02,  "Stereo"},
86
    { 0x03,  "Joint Stereo"},
87
    { 0, NULL }
88
};
89
90
static const value_string allocation_method_vals[] = {
91
    { 0x00,  "Loudness"},
92
    { 0x01,  "SNR"},
93
    { 0, NULL }
94
};
95
96
static const value_string subbands_vals[] = {
97
    { 0x00,  "4"},
98
    { 0x01,  "8"},
99
    { 0, NULL }
100
};
101
102
103
static int
104
dissect_sbc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
105
0
{
106
0
    proto_item  *ti;
107
0
    proto_tree  *sbc_tree;
108
0
    proto_item  *pitem;
109
0
    proto_tree  *rtree;
110
0
    int         offset = 0;
111
0
    uint8_t     number_of_frames;
112
0
    uint8_t     syncword;
113
0
    uint8_t     byte;
114
0
    uint8_t     blocks;
115
0
    uint8_t     channels;
116
0
    uint8_t     subbands;
117
0
    uint8_t     bitpool;
118
0
    unsigned    frequency;
119
0
    uint8_t     sbc_blocks;
120
0
    int         sbc_channels;
121
0
    uint8_t     sbc_subbands;
122
0
    int         val;
123
0
    int         counter = 1;
124
0
    int         frame_length;
125
0
    int         expected_speed_data;
126
0
    double      frame_duration;
127
0
    double      cumulative_frame_duration = 0;
128
0
    bta2dp_codec_info_t  *info;
129
130
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "SBC");
131
132
0
    info = (bta2dp_codec_info_t *) data;
133
134
0
    ti = proto_tree_add_item(tree, proto_sbc, tvb, offset, -1, ENC_NA);
135
0
    sbc_tree = proto_item_add_subtree(ti, ett_sbc);
136
137
0
    proto_tree_add_item(sbc_tree, hf_sbc_fragmented,       tvb, offset, 1, ENC_BIG_ENDIAN);
138
0
    proto_tree_add_item(sbc_tree, hf_sbc_starting_packet,  tvb, offset, 1, ENC_BIG_ENDIAN);
139
0
    proto_tree_add_item(sbc_tree, hf_sbc_last_packet,      tvb, offset, 1, ENC_BIG_ENDIAN);
140
0
    proto_tree_add_item(sbc_tree, hf_sbc_rfa,              tvb, offset, 1, ENC_BIG_ENDIAN);
141
0
    proto_tree_add_item(sbc_tree, hf_sbc_number_of_frames, tvb, offset, 1, ENC_BIG_ENDIAN);
142
0
    number_of_frames = tvb_get_uint8(tvb, offset) & 0x0F;
143
0
    offset += 1;
144
145
0
    while (tvb_reported_length_remaining(tvb, offset) > 0) {
146
0
        byte = tvb_get_uint8(tvb, offset + 1);
147
0
        frequency = (byte & 0xC0) >> 6;
148
0
        blocks = (byte & 0x30) >> 4;
149
0
        channels = (byte & 0x0C)>> 2;
150
0
        subbands = byte & 0x01;
151
152
0
        bitpool = tvb_get_uint8(tvb, offset + 2);
153
154
0
        if (channels == CHANNELS_MONO)
155
0
            sbc_channels = 1;
156
0
        else
157
0
            sbc_channels = 2;
158
159
0
        switch (frequency) {
160
0
            case FREQUENCY_16000:
161
0
                frequency = 16000;
162
0
                break;
163
0
            case FREQUENCY_32000:
164
0
                frequency = 32000;
165
0
                break;
166
0
            case FREQUENCY_44100:
167
0
                frequency = 44100;
168
0
                break;
169
0
            case FREQUENCY_48000:
170
0
                frequency = 48000;
171
0
                break;
172
0
            default:
173
0
                frequency = 0;
174
0
        }
175
176
0
        sbc_subbands = 4 * (subbands + 1);
177
0
        sbc_blocks = 4 * (blocks + 1);
178
179
0
        frame_length = (4 * sbc_subbands * sbc_channels) / 8;
180
0
        if (sbc_channels == 1 || channels == CHANNELS_DUAL_CHANNEL)
181
0
            val = sbc_blocks * sbc_channels * bitpool;
182
0
        else
183
0
            val = (((channels == CHANNELS_JOINT_STEREO) ? 1 : 0) * sbc_subbands + sbc_blocks * bitpool);
184
185
0
        frame_length += val / 8;
186
0
        if (val % 8)
187
0
            frame_length += 1;
188
189
0
        expected_speed_data = (frame_length * frequency) / (sbc_subbands * sbc_blocks);
190
191
0
        rtree = proto_tree_add_subtree_format(sbc_tree, tvb, offset, 4 + frame_length,
192
0
                ett_sbc_list, NULL, "Frame: %3u/%3u", counter, number_of_frames);
193
194
0
        pitem = proto_tree_add_item(rtree, hf_sbc_syncword, tvb, offset, 1, ENC_BIG_ENDIAN);
195
0
        syncword = tvb_get_uint8(tvb, offset);
196
0
        if (syncword != 0x9C) {
197
0
            expert_add_info(pinfo, pitem, &ei_sbc_syncword);
198
0
        }
199
0
        offset += 1;
200
201
0
        proto_tree_add_item(rtree, hf_sbc_sampling_frequency, tvb, offset, 1, ENC_BIG_ENDIAN);
202
0
        proto_tree_add_item(rtree, hf_sbc_blocks,             tvb, offset, 1, ENC_BIG_ENDIAN);
203
0
        proto_tree_add_item(rtree, hf_sbc_channel_mode,       tvb, offset, 1, ENC_BIG_ENDIAN);
204
0
        proto_tree_add_item(rtree, hf_sbc_allocation_method,  tvb, offset, 1, ENC_BIG_ENDIAN);
205
0
        proto_tree_add_item(rtree, hf_sbc_subbands,           tvb, offset, 1, ENC_BIG_ENDIAN);
206
0
        offset += 1;
207
208
0
        proto_tree_add_item(rtree, hf_sbc_bitpool,            tvb, offset, 1, ENC_BIG_ENDIAN);
209
0
        offset += 1;
210
211
0
        proto_tree_add_item(rtree, hf_sbc_crc_check,          tvb, offset, 1, ENC_BIG_ENDIAN);
212
0
        offset += 1;
213
214
0
        proto_tree_add_item(rtree, hf_sbc_data,  tvb, offset, frame_length, ENC_NA);
215
0
        offset += frame_length;
216
217
/* TODO: expert_info for invalid CRC */
218
219
0
        pitem = proto_tree_add_uint(rtree, hf_sbc_expected_data_speed, tvb, offset, 0, expected_speed_data / 1024);
220
0
        proto_item_set_generated(pitem);
221
222
0
        frame_duration = (((double) frame_length / (double) expected_speed_data) * 1000.0);
223
0
        cumulative_frame_duration += frame_duration;
224
225
0
        pitem = proto_tree_add_double(rtree, hf_sbc_frame_duration, tvb, offset, 0, frame_duration);
226
0
        proto_item_set_generated(pitem);
227
228
0
        counter += 1;
229
0
    }
230
231
0
    pitem = proto_tree_add_double(sbc_tree, hf_sbc_cumulative_frame_duration, tvb, offset, 0, cumulative_frame_duration);
232
0
    proto_item_set_generated(pitem);
233
234
0
    if (info && info->configuration && info->configuration_length > 0) {
235
/* TODO: display current codec configuration */
236
0
    }
237
238
0
    if (info && info->previous_media_packet_info && info->current_media_packet_info) {
239
0
        nstime_t  delta;
240
241
0
        nstime_delta(&delta, &pinfo->abs_ts, &info->previous_media_packet_info->abs_ts);
242
0
        pitem = proto_tree_add_double(sbc_tree, hf_sbc_delta_time, tvb, offset, 0, nstime_to_msec(&delta));
243
0
        proto_item_set_generated(pitem);
244
245
0
        pitem = proto_tree_add_double(sbc_tree, hf_sbc_avrcp_song_position, tvb, offset, 0, info->previous_media_packet_info->avrcp_song_position);
246
0
        proto_item_set_generated(pitem);
247
248
0
        nstime_delta(&delta, &pinfo->abs_ts, &info->previous_media_packet_info->first_abs_ts);
249
0
        pitem = proto_tree_add_double(sbc_tree, hf_sbc_delta_time_from_the_beginning, tvb, offset, 0,  nstime_to_msec(&delta));
250
0
        proto_item_set_generated(pitem);
251
252
0
        if (!pinfo->fd->visited) {
253
0
            info->current_media_packet_info->cumulative_frame_duration += cumulative_frame_duration;
254
0
            info->current_media_packet_info->avrcp_song_position        += cumulative_frame_duration;
255
0
        }
256
257
0
        pitem = proto_tree_add_double(sbc_tree, hf_sbc_cumulative_duration, tvb, offset, 0, info->previous_media_packet_info->cumulative_frame_duration);
258
0
        proto_item_set_generated(pitem);
259
260
0
        pitem = proto_tree_add_double(sbc_tree, hf_sbc_diff, tvb, offset, 0, info->previous_media_packet_info->cumulative_frame_duration - nstime_to_msec(&delta));
261
0
        proto_item_set_generated(pitem);
262
0
    }
263
264
/* TODO: more precise dissection: blocks, channels, subbands, padding  */
265
266
0
    col_append_fstr(pinfo->cinfo, COL_INFO, " Frames=%u", number_of_frames);
267
268
0
    return offset;
269
0
}
270
271
void
272
proto_register_sbc(void)
273
15
{
274
15
    module_t *module;
275
15
    expert_module_t* expert_sbc;
276
277
15
    static hf_register_info hf[] = {
278
15
        { &hf_sbc_fragmented,
279
15
            { "Fragmented",                      "sbc.fragmented",
280
15
            FT_BOOLEAN, 8, NULL, 0x80,
281
15
            NULL, HFILL }
282
15
        },
283
15
        { &hf_sbc_starting_packet,
284
15
            { "Starting Packet",                 "sbc.starting_packet",
285
15
            FT_BOOLEAN, 8, NULL, 0x40,
286
15
            NULL, HFILL }
287
15
        },
288
15
        { &hf_sbc_last_packet,
289
15
            { "Last Packet",                     "sbc.last_packet",
290
15
            FT_BOOLEAN, 8, NULL, 0x20,
291
15
            NULL, HFILL }
292
15
        },
293
15
        { &hf_sbc_rfa,
294
15
            { "RFA",                             "sbc.rfa",
295
15
            FT_BOOLEAN, 8, NULL, 0x10,
296
15
            NULL, HFILL }
297
15
        },
298
15
        { &hf_sbc_number_of_frames,
299
15
            { "Number of Frames",                "sbc.number_of_frames",
300
15
            FT_UINT8, BASE_DEC, NULL, 0x0F,
301
15
            NULL, HFILL }
302
15
        },
303
15
        { &hf_sbc_syncword,
304
15
            { "Sync Word",                       "sbc.syncword",
305
15
            FT_UINT8, BASE_HEX, NULL, 0x00,
306
15
            NULL, HFILL }
307
15
        },
308
15
        { &hf_sbc_sampling_frequency,
309
15
            { "Sampling Frequency",              "sbc.sampling_frequency",
310
15
            FT_UINT8, BASE_HEX, VALS(sampling_frequency_vals), 0xC0,
311
15
            NULL, HFILL }
312
15
        },
313
15
        { &hf_sbc_blocks,
314
15
            { "Blocks",                          "sbc.blocks",
315
15
            FT_UINT8, BASE_HEX, VALS(blocks_vals), 0x30,
316
15
            NULL, HFILL }
317
15
        },
318
15
        { &hf_sbc_channel_mode,
319
15
            { "Channel Mode",                    "sbc.channel_mode",
320
15
            FT_UINT8, BASE_HEX, VALS(channel_mode_vals), 0x0C,
321
15
            NULL, HFILL }
322
15
        },
323
15
        { &hf_sbc_allocation_method,
324
15
            { "Allocation Method",               "sbc.allocation_method",
325
15
            FT_UINT8, BASE_HEX, VALS(allocation_method_vals), 0x02,
326
15
            NULL, HFILL }
327
15
        },
328
15
        { &hf_sbc_subbands,
329
15
            { "Subbands",                        "sbc.subbands",
330
15
            FT_UINT8, BASE_HEX, VALS(subbands_vals), 0x01,
331
15
            NULL, HFILL }
332
15
        },
333
15
        { &hf_sbc_bitpool,
334
15
            { "Bitpool",                         "sbc.bitpool",
335
15
            FT_UINT8, BASE_DEC, NULL, 0x00,
336
15
            NULL, HFILL }
337
15
        },
338
15
        { &hf_sbc_crc_check,
339
15
            { "CRC Check",                       "sbc.crc_check",
340
15
            FT_UINT8, BASE_HEX, NULL, 0x00,
341
15
            NULL, HFILL }
342
15
        },
343
15
        { &hf_sbc_expected_data_speed,
344
15
            { "Expected data speed",             "sbc.expected_data_speed",
345
15
            FT_UINT32, BASE_DEC|BASE_UNIT_STRING, UNS(&units_kibps), 0x00,
346
15
            NULL, HFILL }
347
15
        },
348
15
        { &hf_sbc_frame_duration,
349
15
            { "Frame Duration",                  "sbc.frame_duration",
350
15
            FT_DOUBLE, BASE_NONE|BASE_UNIT_STRING, UNS(&units_milliseconds), 0x00,
351
15
            NULL, HFILL }
352
15
        },
353
15
        { &hf_sbc_cumulative_frame_duration,
354
15
            { "Cumulative Frame Duration",      "sbc.cumulative_frame_duration",
355
15
            FT_DOUBLE, BASE_NONE|BASE_UNIT_STRING, UNS(&units_milliseconds), 0x00,
356
15
            NULL, HFILL }
357
15
        },
358
15
        { &hf_sbc_delta_time,
359
15
            { "Delta time",                      "sbc.delta_time",
360
15
            FT_DOUBLE, BASE_NONE|BASE_UNIT_STRING, UNS(&units_milliseconds), 0x00,
361
15
            NULL, HFILL }
362
15
        },
363
15
        { &hf_sbc_delta_time_from_the_beginning,
364
15
            { "Delta time from the beginning",   "sbc.delta_time_from_the_beginning",
365
15
            FT_DOUBLE, BASE_NONE|BASE_UNIT_STRING, UNS(&units_milliseconds), 0x00,
366
15
            NULL, HFILL }
367
15
        },
368
15
        { &hf_sbc_cumulative_duration,
369
15
            { "Cumulative Music Duration",      "sbc.cumulative_music_duration",
370
15
            FT_DOUBLE, BASE_NONE|BASE_UNIT_STRING, UNS(&units_milliseconds), 0x00,
371
15
            NULL, HFILL }
372
15
        },
373
15
        { &hf_sbc_avrcp_song_position,
374
15
            { "AVRCP Song Position",             "sbc.avrcp_song_position",
375
15
            FT_DOUBLE, BASE_NONE|BASE_UNIT_STRING, UNS(&units_milliseconds), 0x00,
376
15
            NULL, HFILL }
377
15
        },
378
15
        { &hf_sbc_diff,
379
15
            { "Diff",            "sbc.diff",
380
15
            FT_DOUBLE, BASE_NONE|BASE_UNIT_STRING, UNS(&units_milliseconds), 0x00,
381
15
            NULL, HFILL }
382
15
        },
383
15
        { &hf_sbc_data,
384
15
            { "Frame Data",                      "sbc.data",
385
15
            FT_NONE, BASE_NONE, NULL, 0x00,
386
15
            NULL, HFILL }
387
15
        },
388
15
    };
389
390
15
    static int *ett[] = {
391
15
        &ett_sbc,
392
15
        &ett_sbc_list,
393
15
    };
394
395
15
    static ei_register_info ei[] = {
396
15
        { &ei_sbc_syncword, { "sbc.syncword.unexpected", PI_PROTOCOL, PI_WARN, "Unexpected syncword", EXPFILL }},
397
15
    };
398
399
15
    proto_sbc = proto_register_protocol("Bluetooth SBC Codec", "SBC", "sbc");
400
401
15
    proto_register_field_array(proto_sbc, hf, array_length(hf));
402
15
    proto_register_subtree_array(ett, array_length(ett));
403
15
    expert_sbc = expert_register_protocol(proto_sbc);
404
15
    expert_register_field_array(expert_sbc, ei, array_length(ei));
405
406
15
    register_dissector("sbc", dissect_sbc, proto_sbc);
407
408
    module = prefs_register_protocol_subtree("Bluetooth", proto_sbc, NULL);
409
15
    prefs_register_static_text_preference(module, "a2dp.version",
410
15
            "Bluetooth Audio Codec SBC version based on A2DP 1.3",
411
15
            "Version of codec supported by this dissector.");
412
15
}
413
414
/*
415
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
416
 *
417
 * Local variables:
418
 * c-basic-offset: 4
419
 * tab-width: 8
420
 * indent-tabs-mode: nil
421
 * End:
422
 *
423
 * vi: set shiftwidth=4 tabstop=8 expandtab:
424
 * :indentSize=4:tabSize=8:noTabs=true:
425
 */