Coverage Report

Created: 2026-01-02 06:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-btavctp.c
Line
Count
Source
1
/* packet-btavctp.c
2
 * Routines for Bluetooth AVCTP 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/prefs.h>
17
#include <epan/expert.h>
18
#include <epan/decode_as.h>
19
#include <epan/proto_data.h>
20
21
#include "packet-bluetooth.h"
22
#include "packet-btl2cap.h"
23
#include "packet-btsdp.h"
24
#include "packet-btavctp.h"
25
26
5
#define PACKET_TYPE_SINGLE    0x00
27
4
#define PACKET_TYPE_START     0x01
28
0
#define PACKET_TYPE_CONTINUE  0x02
29
0
#define PACKET_TYPE_END       0x03
30
31
int proto_btavctp;
32
33
static int hf_btavctp_transaction;
34
static int hf_btavctp_packet_type;
35
static int hf_btavctp_cr;
36
static int hf_btavctp_ipid;
37
static int hf_btavctp_rfa;
38
static int hf_btavctp_pid;
39
static int hf_btavctp_number_of_packets;
40
41
static int ett_btavctp;
42
43
static expert_field ei_btavctp_unexpected_frame;
44
static expert_field ei_btavctp_invalid_profile;
45
46
static dissector_handle_t btavctp_handle;
47
48
typedef struct _fragment_t {
49
    unsigned   length;
50
    uint8_t *data;
51
} fragment_t;
52
53
typedef struct _fragments_t {
54
    uint32_t     interface_id;
55
    uint32_t     adapter_id;
56
    uint32_t     chandle;
57
    uint32_t     psm;
58
    uint32_t     count;
59
    uint32_t     number_of_packets;
60
    uint32_t     pid;
61
    wmem_tree_t  *fragment;
62
} fragments_t;
63
64
static wmem_tree_t *reassembling;
65
static fragments_t *fragments;
66
67
static const value_string packet_type_vals[] = {
68
    { PACKET_TYPE_SINGLE,   "Single" },
69
    { PACKET_TYPE_START,    "Start" },
70
    { PACKET_TYPE_CONTINUE, "Continue" },
71
    { PACKET_TYPE_END,      "End" },
72
    { 0, NULL }
73
};
74
75
static const value_string cr_vals[] = {
76
    { 0x00,   "Command" },
77
    { 0x01,   "Response" },
78
    { 0, NULL }
79
};
80
81
static const value_string ipid_vals[] = {
82
    { 0x00,   "Profile OK" },
83
    { 0x01,   "Invalid profile" },
84
    { 0, NULL }
85
};
86
87
void proto_register_btavctp(void);
88
void proto_reg_handoff_btavctp(void);
89
90
static int
91
dissect_btavctp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
92
1
{
93
1
    proto_item      *ti;
94
1
    proto_tree      *btavctp_tree;
95
1
    proto_item      *pitem;
96
1
    proto_item      *ipid_item = NULL;
97
1
    btavctp_data_t  *avctp_data;
98
1
    tvbuff_t        *next_tvb;
99
1
    int             offset = 0;
100
1
    unsigned        packet_type;
101
1
    unsigned        cr;
102
1
    unsigned        pid = 0;
103
1
    unsigned        transaction;
104
1
    unsigned        number_of_packets = 0;
105
1
    unsigned        length;
106
1
    unsigned        i_frame;
107
1
    bool            ipid = false;
108
1
    uint32_t        interface_id;
109
1
    uint32_t        adapter_id;
110
1
    uint32_t        chandle;
111
1
    uint32_t        psm;
112
1
    int             previous_proto;
113
114
1
    previous_proto = (GPOINTER_TO_INT(wmem_list_frame_data(wmem_list_frame_prev(wmem_list_tail(pinfo->layers)))));
115
1
    if (previous_proto == proto_btl2cap) {
116
1
        btl2cap_data_t  *l2cap_data;
117
118
1
        l2cap_data = (btl2cap_data_t *) data;
119
120
1
        interface_id = l2cap_data->interface_id;
121
1
        adapter_id   = l2cap_data->adapter_id;
122
1
        chandle      = l2cap_data->chandle;
123
1
        psm          = l2cap_data->psm;
124
1
    } else {
125
0
        interface_id = HCI_INTERFACE_DEFAULT;
126
0
        adapter_id   = HCI_ADAPTER_DEFAULT;
127
0
        chandle      = 0;
128
0
        psm          = 0;
129
0
    }
130
131
1
    ti = proto_tree_add_item(tree, proto_btavctp, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA);
132
1
    btavctp_tree = proto_item_add_subtree(ti, ett_btavctp);
133
134
1
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "AVCTP");
135
1
    col_clear(pinfo->cinfo, COL_INFO);
136
137
1
    switch (pinfo->p2p_dir) {
138
0
        case P2P_DIR_SENT:
139
0
            col_set_str(pinfo->cinfo, COL_INFO, "Sent ");
140
0
            break;
141
0
        case P2P_DIR_RECV:
142
0
            col_set_str(pinfo->cinfo, COL_INFO, "Rcvd ");
143
0
            break;
144
1
        default:
145
1
            col_set_str(pinfo->cinfo, COL_INFO, "UnknownDirection ");
146
1
            break;
147
1
    }
148
149
1
    proto_tree_add_item(btavctp_tree, hf_btavctp_transaction,  tvb, offset, 1, ENC_BIG_ENDIAN);
150
1
    pitem = proto_tree_add_item(btavctp_tree, hf_btavctp_packet_type,  tvb, offset, 1, ENC_BIG_ENDIAN);
151
1
    proto_tree_add_item(btavctp_tree, hf_btavctp_cr,  tvb, offset, 1, ENC_BIG_ENDIAN);
152
1
    transaction = tvb_get_uint8(tvb, offset) >> 4;
153
1
    packet_type = (tvb_get_uint8(tvb, offset) & 0x0C) >> 2;
154
1
    cr = (tvb_get_uint8(tvb, offset) & 0x02) >> 1 ;
155
156
1
    if (packet_type == PACKET_TYPE_SINGLE || packet_type == PACKET_TYPE_START) {
157
1
        ipid_item = proto_tree_add_item(btavctp_tree, hf_btavctp_ipid,  tvb, offset, 1, ENC_BIG_ENDIAN);
158
1
        ipid = tvb_get_uint8(tvb, offset) & 0x01;
159
1
    } else {
160
0
        proto_tree_add_item(btavctp_tree, hf_btavctp_rfa,  tvb, offset, 1, ENC_BIG_ENDIAN);
161
0
    }
162
1
    offset++;
163
164
1
    if (packet_type == PACKET_TYPE_START) {
165
1
        proto_tree_add_item(btavctp_tree, hf_btavctp_number_of_packets,  tvb, offset, 1, ENC_BIG_ENDIAN);
166
1
        number_of_packets = tvb_get_uint8(tvb, offset);
167
1
        offset++;
168
1
    }
169
170
1
    if (packet_type == PACKET_TYPE_SINGLE || packet_type == PACKET_TYPE_START) {
171
1
        proto_tree_add_item(btavctp_tree, hf_btavctp_pid,  tvb, offset, 2, ENC_BIG_ENDIAN);
172
1
        pid = tvb_get_ntohs(tvb, offset);
173
174
1
        if (p_get_proto_data(pinfo->pool, pinfo, proto_bluetooth, PROTO_DATA_BLUETOOTH_SERVICE_UUID ) == NULL) {
175
1
            char *value_data;
176
1
            bluetooth_uuid_t  uuid;
177
178
1
            uuid.size = 2;
179
1
            uuid.bt_uuid = pid;
180
1
            uuid.data[0] = pid >> 8;
181
1
            uuid.data[1] = pid & 0xFF;
182
183
1
            value_data = wmem_strdup(wmem_file_scope(), print_numeric_bluetooth_uuid(pinfo->pool, &uuid));
184
185
1
            p_add_proto_data(pinfo->pool, pinfo, proto_bluetooth, PROTO_DATA_BLUETOOTH_SERVICE_UUID, value_data);
186
1
        }
187
1
        offset +=2;
188
1
    }
189
190
1
    col_append_fstr(pinfo->cinfo, COL_INFO, "%s - Transaction: %u, PacketType: %s",
191
1
            val_to_str_const(cr, cr_vals, "unknown CR"), transaction,
192
1
            val_to_str_const(packet_type, packet_type_vals, "unknown packet type"));
193
194
1
    if (ipid) {
195
0
        expert_add_info(pinfo, ipid_item, &ei_btavctp_invalid_profile);
196
0
        col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "Invalid profile");
197
0
        if (tvb_captured_length_remaining(tvb, offset) == 0)
198
0
            return offset;
199
0
    }
200
201
1
    avctp_data = wmem_new(pinfo->pool, btavctp_data_t);
202
1
    avctp_data->cr           = cr;
203
1
    avctp_data->interface_id = interface_id;
204
1
    avctp_data->adapter_id   = adapter_id;
205
1
    avctp_data->chandle      = chandle;
206
1
    avctp_data->psm          = psm;
207
208
1
    length = tvb_reported_length_remaining(tvb, offset);
209
210
    /* reassembling */
211
1
    next_tvb = tvb_new_subset_length(tvb, offset, length);
212
1
    if (packet_type == PACKET_TYPE_SINGLE) {
213
0
        bluetooth_uuid_t  uuid;
214
215
0
        uuid.size = 2;
216
0
        uuid.bt_uuid = pid;
217
0
        uuid.data[0] = pid >> 8;
218
0
        uuid.data[1] = pid & 0xFF;
219
220
0
        if (!dissector_try_string_with_data(bluetooth_uuid_table, print_numeric_bluetooth_uuid(pinfo->pool, &uuid), next_tvb, pinfo, tree, true, avctp_data)) {
221
0
            call_data_dissector(next_tvb, pinfo, tree);
222
0
        }
223
224
1
    } else {
225
1
        fragment_t     *fragment;
226
1
        wmem_tree_key_t key[6];
227
1
        uint32_t        frame_number;
228
229
1
        frame_number = pinfo->num;
230
231
1
        key[0].length = 1;
232
1
        key[0].key = &interface_id;
233
1
        key[1].length = 1;
234
1
        key[1].key = &adapter_id;
235
1
        key[2].length = 1;
236
1
        key[2].key = &chandle;
237
1
        key[3].length = 1;
238
1
        key[3].key = &psm;
239
1
        key[4].length = 1;
240
1
        key[4].key = &frame_number;
241
1
        key[5].length = 0;
242
1
        key[5].key = NULL;
243
244
1
        if (packet_type == PACKET_TYPE_START) {
245
1
            if (!pinfo->fd->visited) {
246
1
                fragment = wmem_new(wmem_file_scope(), fragment_t);
247
1
                fragment->length = length;
248
1
                fragment->data = (uint8_t *) wmem_alloc(wmem_file_scope(), fragment->length);
249
1
                tvb_memcpy(tvb, fragment->data, offset, fragment->length);
250
251
1
                fragments = wmem_new(wmem_file_scope(), fragments_t);
252
1
                fragments->number_of_packets = number_of_packets;
253
1
                fragments->pid = pid;
254
255
1
                fragments->count = 1;
256
1
                fragments->fragment = wmem_tree_new(wmem_file_scope());
257
1
                wmem_tree_insert32(fragments->fragment, fragments->count, fragment);
258
259
1
                fragments->interface_id = interface_id;
260
1
                fragments->adapter_id   = adapter_id;
261
1
                fragments->chandle      = chandle;
262
1
                fragments->psm          = psm;
263
264
1
                wmem_tree_insert32_array(reassembling, key, fragments);
265
266
1
            } else {
267
0
                fragments = (fragments_t *)wmem_tree_lookup32_array_le(reassembling, key);
268
0
                if (!(fragments && fragments->interface_id == interface_id &&
269
0
                        fragments->adapter_id == adapter_id &&
270
0
                        fragments->chandle == chandle &&
271
0
                        fragments->psm == psm))
272
0
                    fragments = NULL;
273
0
            }
274
275
1
            call_data_dissector(next_tvb, pinfo, tree);
276
277
1
        } else if (packet_type == PACKET_TYPE_CONTINUE) {
278
0
            fragments = (fragments_t *)wmem_tree_lookup32_array_le(reassembling, key);
279
0
            if (!(fragments && fragments->interface_id == interface_id &&
280
0
                    fragments->adapter_id == adapter_id &&
281
0
                    fragments->chandle == chandle &&
282
0
                    fragments->psm == psm))
283
0
                fragments = NULL;
284
285
0
            if (!pinfo->fd->visited && fragments != NULL) {
286
0
                fragment = wmem_new(wmem_file_scope(), fragment_t);
287
0
                fragment->length = length;
288
0
                fragment->data = (uint8_t *) wmem_alloc(wmem_file_scope(), fragment->length);
289
0
                tvb_memcpy(tvb, fragment->data, offset, fragment->length);
290
291
0
                fragments->count++;
292
0
                wmem_tree_insert32(fragments->fragment, fragments->count, fragment);
293
294
0
                fragments->interface_id = interface_id;
295
0
                fragments->adapter_id   = adapter_id;
296
0
                fragments->chandle      = chandle;
297
0
                fragments->psm          = psm;
298
299
0
                frame_number = pinfo->num;
300
301
0
                key[0].length = 1;
302
0
                key[0].key = &interface_id;
303
0
                key[1].length = 1;
304
0
                key[1].key = &adapter_id;
305
0
                key[2].length = 1;
306
0
                key[2].key = &chandle;
307
0
                key[3].length = 1;
308
0
                key[3].key = &psm;
309
0
                key[4].length = 1;
310
0
                key[4].key = &frame_number;
311
0
                key[5].length = 0;
312
0
                key[5].key = NULL;
313
314
0
                wmem_tree_insert32_array(reassembling, key, fragments);
315
0
            }
316
317
0
            call_data_dissector(next_tvb, pinfo, tree);
318
319
0
        } else if (packet_type == PACKET_TYPE_END) {
320
321
0
            fragments = (fragments_t *)wmem_tree_lookup32_array_le(reassembling, key);
322
0
            if (!(fragments && fragments->interface_id == interface_id &&
323
0
                    fragments->adapter_id == adapter_id &&
324
0
                    fragments->chandle == chandle &&
325
0
                    fragments->psm == psm))
326
0
                fragments = NULL;
327
328
0
            if (!pinfo->fd->visited && fragments != NULL) {
329
0
                fragment = wmem_new(wmem_file_scope(), fragment_t);
330
0
                fragment->length = length;
331
0
                fragment->data = (uint8_t *) wmem_alloc(wmem_file_scope(), fragment->length);
332
0
                tvb_memcpy(tvb, fragment->data, offset, fragment->length);
333
334
0
                fragments->count++;
335
0
                wmem_tree_insert32(fragments->fragment, fragments->count, fragment);
336
337
0
                fragments->interface_id = interface_id;
338
0
                fragments->adapter_id   = adapter_id;
339
0
                fragments->chandle      = chandle;
340
0
                fragments->psm          = psm;
341
342
0
                frame_number = pinfo->num;
343
344
0
                key[0].length = 1;
345
0
                key[0].key = &interface_id;
346
0
                key[1].length = 1;
347
0
                key[1].key = &adapter_id;
348
0
                key[2].length = 1;
349
0
                key[2].key = &chandle;
350
0
                key[3].length = 1;
351
0
                key[3].key = &psm;
352
0
                key[4].length = 1;
353
0
                key[4].key = &frame_number;
354
0
                key[5].length = 0;
355
0
                key[5].key = NULL;
356
357
0
                wmem_tree_insert32_array(reassembling, key, fragments);
358
0
            }
359
360
0
            length = 0;
361
0
            if (!fragments || fragments->count != fragments->number_of_packets) {
362
0
                expert_add_info(pinfo, pitem, &ei_btavctp_unexpected_frame);
363
0
                call_data_dissector(next_tvb, pinfo, tree);
364
0
            } else {
365
0
                uint8_t  *reassembled = NULL;
366
0
                bluetooth_uuid_t  uuid;
367
368
0
                for (i_frame = 1; i_frame <= fragments->count; ++i_frame) {
369
0
                    fragment = (fragment_t *)wmem_tree_lookup32_le(fragments->fragment, i_frame);
370
0
                    if (fragment) {
371
0
                        reassembled = (uint8_t*)wmem_realloc(pinfo->pool, reassembled, length + fragment->length);
372
0
                        memcpy(reassembled + length, fragment->data, fragment->length);
373
0
                        length += fragment->length;
374
0
                    }
375
0
                }
376
377
0
                next_tvb = tvb_new_child_real_data(tvb, reassembled, length, length);
378
0
                add_new_data_source(pinfo, next_tvb, "Reassembled AVCTP");
379
380
0
                uuid.size = 2;
381
0
                uuid.bt_uuid = fragments->pid;
382
0
                uuid.data[0] = fragments->pid >> 8;
383
0
                uuid.data[1] = fragments->pid & 0xFF;
384
385
0
                if (!dissector_try_string_with_data(bluetooth_uuid_table, print_numeric_bluetooth_uuid(pinfo->pool, &uuid), next_tvb, pinfo, tree, true, avctp_data)) {
386
0
                    call_data_dissector(next_tvb, pinfo, tree);
387
0
                }
388
0
            }
389
390
0
            fragments = NULL;
391
0
        } else {
392
0
            call_data_dissector(next_tvb, pinfo, tree);
393
0
        }
394
1
    }
395
396
1
    return offset;
397
1
}
398
399
void
400
proto_register_btavctp(void)
401
14
{
402
14
    module_t *module;
403
14
    expert_module_t* expert_btavctp;
404
405
14
    static hf_register_info hf[] = {
406
14
        { &hf_btavctp_transaction,
407
14
            { "Transaction",          "btavctp.transaction",
408
14
            FT_UINT8, BASE_HEX, NULL, 0xF0,
409
14
            NULL, HFILL }
410
14
        },
411
14
        { &hf_btavctp_packet_type,
412
14
            { "Packet Type",          "btavctp.packet_type",
413
14
            FT_UINT8, BASE_HEX, VALS(packet_type_vals), 0x0C,
414
14
            NULL, HFILL }
415
14
        },
416
14
        { &hf_btavctp_cr,
417
14
            { "C/R",                  "btavctp.cr",
418
14
            FT_UINT8, BASE_HEX, VALS(cr_vals), 0x02,
419
14
            NULL, HFILL }
420
14
        },
421
14
        { &hf_btavctp_ipid,
422
14
            { "IPID",                 "btavctp.ipid",
423
14
            FT_UINT8, BASE_HEX, VALS(ipid_vals), 0x01,
424
14
            NULL, HFILL }
425
14
        },
426
14
        { &hf_btavctp_rfa,
427
14
            { "RFA",                  "btavctp.rfa",
428
14
            FT_UINT8, BASE_HEX, NULL, 0x01,
429
14
            NULL, HFILL }
430
14
        },
431
14
        { &hf_btavctp_pid,
432
14
            { "Profile Identifier",   "btavctp.pid",
433
14
            FT_UINT16, BASE_HEX|BASE_EXT_STRING, &bluetooth_uuid_vals_ext, 0x00,
434
14
            NULL, HFILL }
435
14
        },
436
14
        { &hf_btavctp_number_of_packets,
437
14
            { "Number of packets",    "btavctp.nop",
438
14
            FT_UINT8, BASE_DEC, NULL, 0x00,
439
14
            NULL, HFILL }
440
14
        }
441
14
    };
442
443
14
    static int *ett[] = {
444
14
        &ett_btavctp
445
14
    };
446
447
14
    static ei_register_info ei[] = {
448
14
        { &ei_btavctp_unexpected_frame, { "btavctp.unexpected_frame", PI_PROTOCOL, PI_WARN, "Unexpected frame", EXPFILL }},
449
14
        { &ei_btavctp_invalid_profile,  { "btavctp.invalid_profile",  PI_PROTOCOL, PI_NOTE, "Invalid Profile", EXPFILL }},
450
14
    };
451
452
    /* Decode As handling */
453
14
    reassembling = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
454
455
14
    proto_btavctp = proto_register_protocol("Bluetooth AVCTP Protocol", "BT AVCTP", "btavctp");
456
14
    btavctp_handle = register_dissector("btavctp", dissect_btavctp, proto_btavctp);
457
458
14
    proto_register_field_array(proto_btavctp, hf, array_length(hf));
459
14
    proto_register_subtree_array(ett, array_length(ett));
460
14
    expert_btavctp = expert_register_protocol(proto_btavctp);
461
14
    expert_register_field_array(expert_btavctp, ei, array_length(ei));
462
463
14
    module = prefs_register_protocol_subtree("Bluetooth", proto_btavctp, NULL);
464
14
    prefs_register_static_text_preference(module, "avctp.version",
465
14
            "Bluetooth Protocol AVCTP version: 1.4",
466
14
            "Version of protocol supported by this dissector.");
467
14
}
468
469
470
void
471
proto_reg_handoff_btavctp(void)
472
14
{
473
14
    dissector_add_string("bluetooth.uuid", "17", btavctp_handle);
474
475
14
    dissector_add_uint("btl2cap.psm", BTL2CAP_PSM_AVCTP_CTRL, btavctp_handle);
476
14
    dissector_add_uint("btl2cap.psm", BTL2CAP_PSM_AVCTP_BRWS, btavctp_handle);
477
478
14
    dissector_add_for_decode_as("btl2cap.cid", btavctp_handle);
479
14
}
480
481
/*
482
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
483
 *
484
 * Local variables:
485
 * c-basic-offset: 4
486
 * tab-width: 8
487
 * indent-tabs-mode: nil
488
 * End:
489
 *
490
 * vi: set shiftwidth=4 tabstop=8 expandtab:
491
 * :indentSize=4:tabSize=8:noTabs=true:
492
 */