Coverage Report

Created: 2025-08-04 07:15

/src/wireshark/epan/dissectors/packet-bthci_acl.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-bthci_acl.c
2
 * Routines for the Bluetooth ACL dissection
3
 * Copyright 2002, Christoph Scholz <scholz@cs.uni-bonn.de>
4
 *     - from: http://affix.sourceforge.net/archive/ethereal_affix-3.patch
5
 * Copyright 2006, Ronnie Sahlberg
6
 *     - refactored for Wireshark checkin
7
 * Copyright 2014, Michal Labedzki for Tieto Corporation
8
 *
9
 * Wireshark - Network traffic analyzer
10
 * By Gerald Combs <gerald@wireshark.org>
11
 * Copyright 1998 Gerald Combs
12
 *
13
 * SPDX-License-Identifier: GPL-2.0-or-later
14
 */
15
16
#include "config.h"
17
18
#include <epan/packet.h>
19
#include <epan/prefs.h>
20
#include <epan/addr_resolv.h>
21
#include <epan/expert.h>
22
#include <epan/proto_data.h>
23
24
#include "packet-bluetooth.h"
25
#include "packet-bthci_acl.h"
26
27
/* Initialize the protocol and registered fields */
28
static int proto_bthci_acl;
29
static int hf_bthci_acl_chandle;
30
static int hf_bthci_acl_pb_flag;
31
static int hf_bthci_acl_bc_flag;
32
static int hf_bthci_acl_length;
33
static int hf_bthci_acl_data;
34
static int hf_bthci_acl_continuation_to;
35
static int hf_bthci_acl_reassembled_in;
36
static int hf_bthci_acl_connect_in;
37
static int hf_bthci_acl_disconnect_in;
38
static int hf_bthci_acl_src_bd_addr;
39
static int hf_bthci_acl_src_name;
40
static int hf_bthci_acl_src_role;
41
static int hf_bthci_acl_dst_bd_addr;
42
static int hf_bthci_acl_dst_name;
43
static int hf_bthci_acl_dst_role;
44
static int hf_bthci_acl_role_last_change_in_frame;
45
static int hf_bthci_acl_mode;
46
static int hf_bthci_acl_mode_last_change_in_frame;
47
48
/* Initialize the subtree pointers */
49
static int ett_bthci_acl;
50
51
static expert_field ei_invalid_session;
52
static expert_field ei_length_bad;
53
54
static dissector_handle_t bthci_acl_handle;
55
static dissector_handle_t btl2cap_handle;
56
57
static bool acl_reassembly = true;
58
59
typedef struct _multi_fragment_pdu_t {
60
    uint32_t first_frame;
61
    uint32_t last_frame;
62
    uint16_t tot_len;
63
    char    *reassembled;
64
    int      cur_off;           /* counter used by reassembly */
65
} multi_fragment_pdu_t;
66
67
typedef struct _chandle_data_t {
68
    wmem_tree_t *start_fragments;  /* indexed by pinfo->num */
69
} chandle_data_t;
70
71
static wmem_tree_t *chandle_tree;
72
73
static const value_string role_vals[] = {
74
    { 0, "Unknown" },
75
    { 1, "Central" },
76
    { 2, "Peripheral" },
77
    { 0, NULL }
78
};
79
80
static const value_string mode_vals[] = {
81
    { 0, "Active Mode" },
82
    { 1, "Hold Mode" },
83
    { 2, "Sniff Mode" },
84
    { 3, "Park Mode" },
85
    {-1, "Unknown" },
86
    { 0, NULL }
87
};
88
89
static const value_string pb_flag_vals[] = {
90
    { 0, "First Non-automatically Flushable Packet" },
91
    { 1, "Continuing Fragment" },
92
    { 2, "First Automatically Flushable Packet" },
93
    { 0, NULL }
94
};
95
96
static const value_string bc_flag_vals[] = {
97
    { 0, "Point-To-Point" },
98
    { 1, "Active Broadcast" },
99
    { 2, "Piconet Broadcast" },
100
    { 0, NULL }
101
};
102
103
static uint32_t invalid_session;
104
105
106
void proto_register_bthci_acl(void);
107
void proto_reg_handoff_bthci_acl(void);
108
109
/* Code to actually dissect the packets */
110
static int
111
dissect_bthci_acl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
112
6
{
113
6
    proto_item               *bthci_acl_item;
114
6
    proto_tree               *bthci_acl_tree;
115
6
    proto_item               *sub_item;
116
6
    proto_item               *length_item;
117
6
    uint16_t                  flags;
118
6
    uint16_t                  length;
119
6
    bool                      fragmented;
120
6
    int                       offset                = 0;
121
6
    uint16_t                  pb_flag, l2cap_length = 0;
122
6
    tvbuff_t                 *next_tvb;
123
6
    bthci_acl_data_t         *acl_data;
124
6
    chandle_data_t           *chandle_data;
125
6
    bluetooth_data_t         *bluetooth_data;
126
6
    wmem_tree_t              *subtree;
127
6
    wmem_tree_key_t           key[6];
128
6
    uint32_t                  interface_id;
129
6
    uint32_t                  adapter_id;
130
6
    uint32_t                  connection_handle;
131
6
    uint32_t                  direction;
132
6
    uint32_t                  k_bd_addr_oui;
133
6
    uint32_t                  k_bd_addr_id;
134
6
    uint32_t                  frame_number;
135
6
    remote_bdaddr_t          *remote_bdaddr;
136
6
    const char               *localhost_name;
137
6
    uint8_t                   localhost_bdaddr[6];
138
6
    const char               *localhost_ether_addr;
139
6
    char                     *localhost_addr_name;
140
6
    int                       localhost_length;
141
6
    localhost_bdaddr_entry_t *localhost_bdaddr_entry;
142
6
    localhost_name_entry_t   *localhost_name_entry;
143
6
    static const uint8_t      unknown_bd_addr[6] = {0};
144
6
    const uint8_t            *src_bd_addr = &unknown_bd_addr[0];
145
6
    const char               *src_name = "";
146
6
    const char               *src_addr_name = "";
147
6
    const uint8_t            *dst_bd_addr = &unknown_bd_addr[0];
148
6
    const char               *dst_name = "";
149
6
    const char               *dst_addr_name = "";
150
6
    chandle_session_t        *chandle_session;
151
6
    uint32_t                  src_role = ROLE_UNKNOWN;
152
6
    uint32_t                  dst_role = ROLE_UNKNOWN;
153
6
    uint32_t                  role_last_change_in_frame = 0;
154
6
    connection_mode_t        *connection_mode;
155
6
    int32_t                   mode = -1;
156
6
    uint32_t                  mode_last_change_in_frame = 0;
157
158
    /* Reject the packet if data is NULL */
159
6
    if (data == NULL)
160
0
        return 0;
161
6
    bluetooth_data = (bluetooth_data_t *) data;
162
163
6
    bthci_acl_item = proto_tree_add_item(tree, proto_bthci_acl, tvb, offset, -1, ENC_NA);
164
6
    bthci_acl_tree = proto_item_add_subtree(bthci_acl_item, ett_bthci_acl);
165
166
6
    switch (pinfo->p2p_dir) {
167
1
        case P2P_DIR_SENT:
168
1
            col_set_str(pinfo->cinfo, COL_INFO, "Sent ");
169
1
            break;
170
0
        case P2P_DIR_RECV:
171
0
            col_set_str(pinfo->cinfo, COL_INFO, "Rcvd ");
172
0
            break;
173
5
        default:
174
5
        col_set_str(pinfo->cinfo, COL_INFO, "UnknownDirection ");
175
5
            break;
176
6
    }
177
178
6
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "HCI_ACL");
179
180
6
    flags   = tvb_get_letohs(tvb, offset);
181
6
    pb_flag = (flags & 0x3000) >> 12;
182
6
    proto_tree_add_item(bthci_acl_tree, hf_bthci_acl_chandle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
183
6
    proto_tree_add_item(bthci_acl_tree, hf_bthci_acl_pb_flag, tvb, offset, 2, ENC_LITTLE_ENDIAN);
184
6
    proto_tree_add_item(bthci_acl_tree, hf_bthci_acl_bc_flag, tvb, offset, 2, ENC_LITTLE_ENDIAN);
185
6
    offset += 2;
186
187
6
    interface_id      = bluetooth_data->interface_id;
188
6
    adapter_id        = bluetooth_data->adapter_id;
189
6
    connection_handle = flags & 0x0fff;
190
6
    direction         = pinfo->p2p_dir;
191
6
    frame_number      = pinfo->num;
192
193
6
    acl_data = wmem_new(pinfo->pool, bthci_acl_data_t);
194
6
    acl_data->interface_id                = interface_id;
195
6
    acl_data->adapter_id                  = adapter_id;
196
6
    acl_data->adapter_disconnect_in_frame = bluetooth_data->adapter_disconnect_in_frame;
197
6
    acl_data->chandle                     = connection_handle;
198
6
    acl_data->is_btle                     = false;
199
6
    acl_data->is_btle_retransmit          = false;
200
201
6
    key[0].length = 1;
202
6
    key[0].key    = &interface_id;
203
6
    key[1].length = 1;
204
6
    key[1].key    = &adapter_id;
205
6
    key[2].length = 1;
206
6
    key[2].key    = &connection_handle;
207
6
    key[3].length = 0;
208
6
    key[3].key    = NULL;
209
210
6
    subtree = (wmem_tree_t *) wmem_tree_lookup32_array(bluetooth_data->chandle_sessions, key);
211
6
    chandle_session = (subtree) ? (chandle_session_t *) wmem_tree_lookup32_le(subtree, pinfo->num) : NULL;
212
6
    if (chandle_session &&
213
6
            chandle_session->connect_in_frame < pinfo->num &&
214
6
            chandle_session->disconnect_in_frame > pinfo->num) {
215
0
        acl_data->disconnect_in_frame = &chandle_session->disconnect_in_frame;
216
6
    } else {
217
6
        acl_data->disconnect_in_frame = &invalid_session;
218
6
        chandle_session = NULL;
219
6
    }
220
221
6
    acl_data->remote_bd_addr_oui         = 0;
222
6
    acl_data->remote_bd_addr_id          = 0;
223
224
6
    subtree = (wmem_tree_t *) wmem_tree_lookup32_array(bluetooth_data->chandle_to_mode, key);
225
6
    connection_mode = (subtree) ? (connection_mode_t *) wmem_tree_lookup32_le(subtree, pinfo->num) : NULL;
226
6
    if (connection_mode) {
227
0
        mode = connection_mode->mode;
228
0
        mode_last_change_in_frame = connection_mode->change_in_frame;
229
0
    }
230
231
    /* remote bdaddr and name */
232
6
    subtree = (wmem_tree_t *) wmem_tree_lookup32_array(bluetooth_data->chandle_to_bdaddr, key);
233
6
    remote_bdaddr = (subtree) ? (remote_bdaddr_t *) wmem_tree_lookup32_le(subtree, pinfo->num) : NULL;
234
6
    if (remote_bdaddr) {
235
0
        uint32_t        bd_addr_oui;
236
0
        uint32_t        bd_addr_id;
237
0
        device_name_t  *device_name;
238
0
        device_role_t  *device_role;
239
0
        const char     *remote_name;
240
0
        const char     *remote_ether_addr;
241
0
        char           *remote_addr_name;
242
0
        int             remote_length;
243
244
0
        bd_addr_oui = remote_bdaddr->bd_addr[0] << 16 | remote_bdaddr->bd_addr[1] << 8 | remote_bdaddr->bd_addr[2];
245
0
        bd_addr_id  = remote_bdaddr->bd_addr[3] << 16 | remote_bdaddr->bd_addr[4] << 8 | remote_bdaddr->bd_addr[5];
246
247
0
        acl_data->remote_bd_addr_oui = bd_addr_oui;
248
0
        acl_data->remote_bd_addr_id  = bd_addr_id;
249
250
0
        k_bd_addr_oui  = bd_addr_oui;
251
0
        k_bd_addr_id   = bd_addr_id;
252
253
0
        key[0].length = 1;
254
0
        key[0].key    = &interface_id;
255
0
        key[1].length = 1;
256
0
        key[1].key    = &adapter_id;
257
0
        key[2].length = 1;
258
0
        key[2].key    = &k_bd_addr_id;
259
0
        key[3].length = 1;
260
0
        key[3].key    = &k_bd_addr_oui;
261
0
        key[4].length = 0;
262
0
        key[4].key    = NULL;
263
264
0
        subtree = (wmem_tree_t *) wmem_tree_lookup32_array(bluetooth_data->bdaddr_to_role, key);
265
0
        device_role = (subtree) ? (device_role_t *) wmem_tree_lookup32_le(subtree, pinfo->num) : NULL;
266
0
        if (device_role) {
267
0
            if ((pinfo->p2p_dir == P2P_DIR_SENT && device_role->role == ROLE_CENTRAL) ||
268
0
                    (pinfo->p2p_dir == P2P_DIR_RECV && device_role->role == ROLE_PERIPHERAL)) {
269
0
                src_role = ROLE_PERIPHERAL;
270
0
                dst_role = ROLE_CENTRAL;
271
0
            } else if ((pinfo->p2p_dir == P2P_DIR_SENT && device_role->role == ROLE_PERIPHERAL) ||
272
0
                    (pinfo->p2p_dir == P2P_DIR_RECV && device_role->role == ROLE_CENTRAL)) {
273
0
                src_role = ROLE_CENTRAL;
274
0
                dst_role = ROLE_PERIPHERAL;
275
0
            }
276
0
            role_last_change_in_frame = device_role->change_in_frame;
277
0
        }
278
279
0
        subtree = (wmem_tree_t *) wmem_tree_lookup32_array(bluetooth_data->bdaddr_to_name, key);
280
0
        device_name = (subtree) ? (device_name_t *) wmem_tree_lookup32_le(subtree, pinfo->num) : NULL;
281
0
        if (device_name)
282
0
            remote_name = device_name->name;
283
0
        else
284
0
            remote_name = "";
285
286
0
        remote_ether_addr = get_ether_name(remote_bdaddr->bd_addr);
287
0
        remote_length = (int)(strlen(remote_ether_addr) + 3 + strlen(remote_name) + 1);
288
0
        remote_addr_name = (char *)wmem_alloc(pinfo->pool, remote_length);
289
290
0
        snprintf(remote_addr_name, remote_length, "%s (%s)", remote_ether_addr, remote_name);
291
292
0
        if (pinfo->p2p_dir == P2P_DIR_RECV) {
293
0
            src_bd_addr   = remote_bdaddr->bd_addr;
294
0
            src_name      = remote_name;
295
0
            src_addr_name = remote_addr_name;
296
0
        } else if (pinfo->p2p_dir == P2P_DIR_SENT) {
297
0
            dst_bd_addr   = remote_bdaddr->bd_addr;
298
0
            dst_name      = remote_name;
299
0
            dst_addr_name = remote_addr_name;
300
0
        }
301
6
    } else {
302
6
        if (pinfo->p2p_dir == P2P_DIR_RECV)
303
0
            src_addr_name = "remote ()";
304
6
        else if (pinfo->p2p_dir == P2P_DIR_SENT)
305
1
            dst_addr_name = "remote ()";
306
6
    }
307
308
    /* localhost bdaddr and name */
309
6
    key[0].length = 1;
310
6
    key[0].key    = &interface_id;
311
6
    key[1].length = 1;
312
6
    key[1].key    = &adapter_id;
313
6
    key[2].length = 0;
314
6
    key[2].key    = NULL;
315
316
317
6
    subtree = (wmem_tree_t *) wmem_tree_lookup32_array(bluetooth_data->localhost_bdaddr, key);
318
6
    localhost_bdaddr_entry = (subtree) ? (localhost_bdaddr_entry_t *) wmem_tree_lookup32_le(subtree, pinfo->num) : NULL;
319
6
    if (localhost_bdaddr_entry) {
320
0
        localhost_ether_addr = get_ether_name(localhost_bdaddr_entry->bd_addr);
321
0
        memcpy(localhost_bdaddr, localhost_bdaddr_entry->bd_addr, 6);
322
6
    } else {
323
6
        localhost_ether_addr = "localhost";
324
6
        memcpy(localhost_bdaddr, unknown_bd_addr, 6);
325
6
    }
326
327
6
    subtree = (wmem_tree_t *) wmem_tree_lookup32_array(bluetooth_data->localhost_name, key);
328
6
    localhost_name_entry = (subtree) ? (localhost_name_entry_t *) wmem_tree_lookup32_le(subtree, pinfo->num) : NULL;
329
6
    if (localhost_name_entry)
330
0
        localhost_name = localhost_name_entry->name;
331
6
    else
332
6
        localhost_name = "";
333
334
6
    localhost_length = (int)(strlen(localhost_ether_addr) + 3 + strlen(localhost_name) + 1);
335
6
    localhost_addr_name = (char *)wmem_alloc(pinfo->pool, localhost_length);
336
337
6
    snprintf(localhost_addr_name, localhost_length, "%s (%s)", localhost_ether_addr, localhost_name);
338
339
6
    if (pinfo->p2p_dir == P2P_DIR_RECV) {
340
0
        dst_bd_addr   = localhost_bdaddr;
341
0
        dst_name      = localhost_name;
342
0
        dst_addr_name = localhost_addr_name;
343
6
    } else if (pinfo->p2p_dir == P2P_DIR_SENT) {
344
1
        src_bd_addr   = localhost_bdaddr;
345
1
        src_name      = localhost_name;
346
1
        src_addr_name = localhost_addr_name;
347
1
    }
348
349
    /* find the chandle_data structure associated with this chandle */
350
6
    key[0].length = 1;
351
6
    key[0].key = &interface_id;
352
6
    key[1].length = 1;
353
6
    key[1].key = &adapter_id;
354
6
    key[2].length = 1;
355
6
    key[2].key = &connection_handle;
356
6
    key[3].length = 1;
357
6
    key[3].key = &direction;
358
6
    key[4].length = 0;
359
6
    key[4].key = NULL;
360
361
6
    subtree = (wmem_tree_t *) wmem_tree_lookup32_array(chandle_tree, key);
362
6
    chandle_data = (subtree) ? (chandle_data_t *) wmem_tree_lookup32_le(subtree, pinfo->num) : NULL;
363
6
    if (!pinfo->fd->visited && !chandle_data) {
364
5
        key[0].length = 1;
365
5
        key[0].key = &interface_id;
366
5
        key[1].length = 1;
367
5
        key[1].key = &adapter_id;
368
5
        key[2].length = 1;
369
5
        key[2].key = &connection_handle;
370
5
        key[3].length = 1;
371
5
        key[3].key = &direction;
372
5
        key[4].length = 1;
373
5
        key[4].key = &frame_number;
374
5
        key[5].length = 0;
375
5
        key[5].key = NULL;
376
377
5
        chandle_data = wmem_new(wmem_file_scope(), chandle_data_t);
378
5
        chandle_data->start_fragments = wmem_tree_new(wmem_file_scope());
379
380
5
        wmem_tree_insert32_array(chandle_tree, key, chandle_data);
381
5
    } else if (pinfo->fd->visited && !chandle_data) {
382
0
        DISSECTOR_ASSERT_HINT(0, "Impossible: no previously session saved");
383
0
    }
384
385
6
    length = tvb_get_letohs(tvb, offset);
386
6
    length_item = proto_tree_add_item(bthci_acl_tree, hf_bthci_acl_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
387
6
    offset += 2;
388
389
    /* determine if packet is fragmented */
390
6
    switch(pb_flag) {
391
1
    case 0x01:  /* Continuation fragment */
392
1
        fragmented = true;
393
1
        break;
394
1
    case 0x00:  /* First fragment/packet, non-auto flushable */
395
4
    case 0x02:  /* First fragment/packet, auto flushable */
396
4
        l2cap_length = tvb_get_letohs(tvb, offset);
397
4
        fragmented   = (l2cap_length + 4 != length);
398
4
        break;
399
1
    default:
400
        /* unknown pb_flag */
401
1
        fragmented = false;
402
6
    }
403
404
6
    alloc_address_wmem(pinfo->pool, &pinfo->net_src, AT_STRINGZ, (int)strlen(src_name) + 1, src_name);
405
6
    alloc_address_wmem(pinfo->pool, &pinfo->dl_src, AT_ETHER, 6, src_bd_addr);
406
6
    alloc_address_wmem(pinfo->pool, &pinfo->src, AT_STRINGZ, (int)strlen(src_addr_name) + 1, src_addr_name);
407
408
6
    alloc_address_wmem(pinfo->pool, &pinfo->net_dst, AT_STRINGZ, (int)strlen(dst_name) + 1, dst_name);
409
6
    alloc_address_wmem(pinfo->pool, &pinfo->dl_dst, AT_ETHER, 6, dst_bd_addr);
410
6
    alloc_address_wmem(pinfo->pool, &pinfo->dst, AT_STRINGZ, (int)strlen(dst_addr_name) + 1, dst_addr_name);
411
412
6
    if (!fragmented || (!acl_reassembly && !(pb_flag & 0x01))) {
413
        /* call L2CAP dissector for PDUs that are not fragmented
414
         * also for the first fragment if reassembly is disabled
415
         */
416
1
        if (length < tvb_captured_length_remaining(tvb, offset)) {
417
0
            expert_add_info(pinfo, length_item, &ei_length_bad);
418
            /* Try to dissect as more as possible */
419
0
            length = tvb_captured_length_remaining(tvb, offset);
420
0
        }
421
422
1
        next_tvb = tvb_new_subset_length_caplen(tvb, offset, tvb_captured_length_remaining(tvb, offset), length);
423
1
        call_dissector_with_data(btl2cap_handle, next_tvb, pinfo, tree, acl_data);
424
5
    } else if (fragmented && acl_reassembly) {
425
5
        multi_fragment_pdu_t *mfp = NULL;
426
5
        int                   len;
427
428
5
        if (!(pb_flag & 0x01)) { /* first fragment */
429
4
            if (!pinfo->fd->visited) {
430
4
                mfp = (multi_fragment_pdu_t *) wmem_new(wmem_file_scope(), multi_fragment_pdu_t);
431
4
                mfp->first_frame = pinfo->num;
432
4
                mfp->last_frame  = 0;
433
4
                mfp->tot_len     = l2cap_length + 4;
434
4
                mfp->reassembled = (char *) wmem_alloc(wmem_file_scope(), mfp->tot_len);
435
4
                len = tvb_captured_length_remaining(tvb, offset);
436
4
                if (len <= mfp->tot_len) {
437
3
                    tvb_memcpy(tvb, (uint8_t *) mfp->reassembled, offset, len);
438
3
                    mfp->cur_off = len;
439
3
                    wmem_tree_insert32(chandle_data->start_fragments, pinfo->num, mfp);
440
3
                }
441
4
            } else {
442
0
                mfp = (multi_fragment_pdu_t *)wmem_tree_lookup32(chandle_data->start_fragments, pinfo->num);
443
0
            }
444
4
            if (mfp != NULL && mfp->last_frame) {
445
0
                proto_item *item;
446
447
0
                item = proto_tree_add_uint(bthci_acl_tree, hf_bthci_acl_reassembled_in, tvb, 0, 0, mfp->last_frame);
448
0
                proto_item_set_generated(item);
449
0
                col_append_frame_number(pinfo, COL_INFO, " [Reassembled in #%u]", mfp->last_frame);
450
0
            }
451
4
        }
452
5
        if (pb_flag == 0x01) { /* continuation fragment */
453
1
            mfp = (multi_fragment_pdu_t *)wmem_tree_lookup32_le(chandle_data->start_fragments, pinfo->num);
454
1
            if (!pinfo->fd->visited) {
455
1
                len = tvb_captured_length_remaining(tvb, offset);
456
1
                if (mfp != NULL && !mfp->last_frame && (mfp->tot_len >= mfp->cur_off + len)) {
457
0
                    tvb_memcpy(tvb, (uint8_t *) mfp->reassembled + mfp->cur_off, offset, len);
458
0
                    mfp->cur_off += len;
459
0
                    if (mfp->cur_off == mfp->tot_len) {
460
0
                        mfp->last_frame = pinfo->num;
461
0
                    }
462
0
                }
463
1
            }
464
1
            if (mfp) {
465
0
                proto_item *item;
466
467
0
                item = proto_tree_add_uint(bthci_acl_tree, hf_bthci_acl_continuation_to, tvb, 0, 0, mfp->first_frame);
468
0
                proto_item_set_generated(item);
469
0
                col_append_frame_number(pinfo, COL_INFO, " [Continuation to #%u]", mfp->first_frame);
470
0
                if (mfp->last_frame && mfp->last_frame != pinfo->num) {
471
0
                    item = proto_tree_add_uint(bthci_acl_tree, hf_bthci_acl_reassembled_in, tvb, 0, 0, mfp->last_frame);
472
0
                    proto_item_set_generated(item);
473
0
                    col_append_frame_number(pinfo, COL_INFO, " [Reassembled in #%u]", mfp->last_frame);
474
0
                }
475
0
            }
476
1
            if (mfp != NULL && mfp->last_frame == pinfo->num) {
477
0
                next_tvb = tvb_new_child_real_data(tvb, (uint8_t *) mfp->reassembled, mfp->tot_len, mfp->tot_len);
478
0
                add_new_data_source(pinfo, next_tvb, "Reassembled BTHCI ACL");
479
480
0
                call_dissector_with_data(btl2cap_handle, next_tvb, pinfo, tree, acl_data);
481
0
            }
482
1
        }
483
5
    }
484
485
6
    if (tvb_captured_length_remaining(tvb, offset) > 0) {
486
6
        sub_item = proto_tree_add_item(bthci_acl_tree, hf_bthci_acl_data, tvb, offset, -1, ENC_NA);
487
6
        if (fragmented) {
488
5
            proto_item_append_text(sub_item, " Fragment");
489
5
        }
490
6
    }
491
492
6
    if (chandle_session) {
493
0
        sub_item = proto_tree_add_uint(bthci_acl_tree, hf_bthci_acl_connect_in, tvb, 0, 0, chandle_session->connect_in_frame);
494
0
        proto_item_set_generated(sub_item);
495
496
0
        if (chandle_session->disconnect_in_frame < UINT32_MAX) {
497
0
            sub_item = proto_tree_add_uint(bthci_acl_tree, hf_bthci_acl_disconnect_in, tvb, 0, 0, chandle_session->disconnect_in_frame);
498
0
            proto_item_set_generated(sub_item);
499
0
        }
500
0
    }
501
502
6
    if (acl_data->disconnect_in_frame == &invalid_session) {
503
6
        expert_add_info(pinfo, bthci_acl_item, &ei_invalid_session);
504
6
    }
505
506
6
    if (!pinfo->fd->visited) {
507
6
        address *addr;
508
509
6
        addr = (address *) wmem_memdup(wmem_file_scope(), &pinfo->dl_src, sizeof(address));
510
6
        addr->data =  wmem_memdup(wmem_file_scope(), pinfo->dl_src.data, pinfo->dl_src.len);
511
6
        p_add_proto_data(wmem_file_scope(), pinfo, proto_bluetooth, BLUETOOTH_DATA_SRC, addr);
512
513
6
        addr = (address *) wmem_memdup(wmem_file_scope(), &pinfo->dl_dst, sizeof(address));
514
6
        addr->data =  wmem_memdup(wmem_file_scope(), pinfo->dl_dst.data, pinfo->dl_dst.len);
515
6
        p_add_proto_data(wmem_file_scope(), pinfo, proto_bluetooth, BLUETOOTH_DATA_DST, addr);
516
6
    }
517
518
6
    sub_item = proto_tree_add_ether(bthci_acl_tree, hf_bthci_acl_src_bd_addr, tvb, 0, 0, src_bd_addr);
519
6
    proto_item_set_generated(sub_item);
520
521
6
    sub_item = proto_tree_add_string(bthci_acl_tree, hf_bthci_acl_src_name, tvb, 0, 0, src_name);
522
6
    proto_item_set_generated(sub_item);
523
524
6
    sub_item = proto_tree_add_uint(bthci_acl_tree, hf_bthci_acl_src_role, tvb, 0, 0, src_role);
525
6
    proto_item_set_generated(sub_item);
526
527
6
    sub_item = proto_tree_add_ether(bthci_acl_tree, hf_bthci_acl_dst_bd_addr, tvb, 0, 0, dst_bd_addr);
528
6
    proto_item_set_generated(sub_item);
529
530
6
    sub_item = proto_tree_add_string(bthci_acl_tree, hf_bthci_acl_dst_name, tvb, 0, 0, dst_name);
531
6
    proto_item_set_generated(sub_item);
532
533
6
    sub_item = proto_tree_add_uint(bthci_acl_tree, hf_bthci_acl_dst_role, tvb, 0, 0, dst_role);
534
6
    proto_item_set_generated(sub_item);
535
536
6
    if (role_last_change_in_frame > 0) {
537
0
        sub_item = proto_tree_add_uint(bthci_acl_tree, hf_bthci_acl_role_last_change_in_frame, tvb, 0, 0, role_last_change_in_frame);
538
0
        proto_item_set_generated(sub_item);
539
0
    }
540
541
6
    sub_item = proto_tree_add_int(bthci_acl_tree, hf_bthci_acl_mode, tvb, 0, 0, mode);
542
6
    proto_item_set_generated(sub_item);
543
544
6
    if (mode_last_change_in_frame > 0) {
545
0
        sub_item = proto_tree_add_uint(bthci_acl_tree, hf_bthci_acl_mode_last_change_in_frame, tvb, 0, 0, mode_last_change_in_frame);
546
0
        proto_item_set_generated(sub_item);
547
0
    }
548
549
6
    return tvb_captured_length(tvb);
550
6
}
551
552
553
void
554
proto_register_bthci_acl(void)
555
14
{
556
14
    module_t         *bthci_acl_module;
557
14
    expert_module_t  *bthci_acl_expert_module;
558
    /* Setup list of header fields  See Section 1.6.1 for details*/
559
14
    static hf_register_info hf[] = {
560
14
        { &hf_bthci_acl_chandle,
561
14
          { "Connection Handle",                             "bthci_acl.chandle",
562
14
            FT_UINT16, BASE_HEX, NULL, 0x0FFF,
563
14
            NULL, HFILL }
564
14
        },
565
14
        { &hf_bthci_acl_pb_flag,
566
14
          { "PB Flag",                                       "bthci_acl.pb_flag",
567
14
            FT_UINT16, BASE_DEC, VALS(pb_flag_vals), 0x3000,
568
14
            "Packet Boundary Flag", HFILL }
569
14
        },
570
14
        { &hf_bthci_acl_bc_flag,
571
14
          { "BC Flag",                                       "bthci_acl.bc_flag",
572
14
            FT_UINT16, BASE_DEC, VALS(bc_flag_vals), 0xC000,
573
14
            "Broadcast Flag", HFILL }
574
14
        },
575
14
        { &hf_bthci_acl_length,
576
14
          { "Data Total Length",                             "bthci_acl.length",
577
14
            FT_UINT16, BASE_DEC, NULL, 0x0,
578
14
            NULL, HFILL }
579
14
        },
580
14
        { &hf_bthci_acl_data,
581
14
          { "Data",                                          "bthci_acl.data",
582
14
            FT_NONE, BASE_NONE, NULL, 0x0,
583
14
            NULL, HFILL }
584
14
        },
585
14
        { &hf_bthci_acl_continuation_to,
586
14
          { "This is a continuation to the PDU in frame",    "bthci_acl.continuation_to",
587
14
            FT_FRAMENUM, BASE_NONE, NULL, 0x0,
588
14
            "This is a continuation to the PDU in frame #", HFILL }
589
14
        },
590
14
        { &hf_bthci_acl_reassembled_in,
591
14
          { "This PDU is reassembled in frame",              "bthci_acl.reassembled_in",
592
14
            FT_FRAMENUM, BASE_NONE, NULL, 0x0,
593
14
            "This PDU is reassembled in frame #", HFILL }
594
14
        },
595
14
        { &hf_bthci_acl_connect_in,
596
14
            { "Connect in frame",                            "bthci_acl.connect_in",
597
14
            FT_FRAMENUM, BASE_NONE, NULL, 0x0,
598
14
            NULL, HFILL }
599
14
        },
600
14
        { &hf_bthci_acl_disconnect_in,
601
14
            { "Disconnect in frame",                         "bthci_acl.disconnect_in",
602
14
            FT_FRAMENUM, BASE_NONE, NULL, 0x0,
603
14
            NULL, HFILL }
604
14
        },
605
14
        { &hf_bthci_acl_src_bd_addr,
606
14
            { "Source BD_ADDR",                              "bthci_acl.src.bd_addr",
607
14
            FT_ETHER, BASE_NONE, NULL, 0x0,
608
14
            NULL, HFILL }
609
14
        },
610
14
        { &hf_bthci_acl_src_name,
611
14
            { "Source Device Name",                          "bthci_acl.src.name",
612
14
            FT_STRINGZ, BASE_NONE, NULL, 0x0,
613
14
            NULL, HFILL }
614
14
        },
615
14
        { &hf_bthci_acl_src_role,
616
14
            { "Source Role",                                "bthci_acl.src.role",
617
14
            FT_UINT32, BASE_DEC, VALS(role_vals), 0x0,
618
14
            NULL, HFILL }
619
14
        },
620
14
        { &hf_bthci_acl_dst_bd_addr,
621
14
            { "Destination BD_ADDR",                         "bthci_acl.dst.bd_addr",
622
14
            FT_ETHER, BASE_NONE, NULL, 0x0,
623
14
            NULL, HFILL }
624
14
        },
625
14
        { &hf_bthci_acl_dst_name,
626
14
            { "Destination Device Name",                     "bthci_acl.dst.name",
627
14
            FT_STRINGZ, BASE_NONE, NULL, 0x0,
628
14
            NULL, HFILL }
629
14
        },
630
14
        { &hf_bthci_acl_dst_role,
631
14
            { "Destination Role",                            "bthci_acl.dst.role",
632
14
            FT_UINT32, BASE_DEC, VALS(role_vals), 0x0,
633
14
            NULL, HFILL }
634
14
        },
635
14
        { &hf_bthci_acl_role_last_change_in_frame,
636
14
            { "Last Role Change in Frame",                   "bthci_acl.last_change_in_frame.role",
637
14
            FT_FRAMENUM, BASE_NONE, NULL, 0x0,
638
14
            NULL, HFILL }
639
14
        },
640
14
        { &hf_bthci_acl_mode,
641
14
            { "Current Mode",                                "bthci_acl.mode",
642
14
            FT_INT32, BASE_DEC, VALS(mode_vals), 0x0,
643
14
            NULL, HFILL }
644
14
        },
645
14
        { &hf_bthci_acl_mode_last_change_in_frame,
646
14
            { "Last Mode Change in Frame",                   "bthci_acl.last_change_in_frame.mode",
647
14
            FT_FRAMENUM, BASE_NONE, NULL, 0x0,
648
14
            NULL, HFILL }
649
14
        },
650
14
    };
651
652
    /* Setup protocol subtree array */
653
14
    static int *ett[] = {
654
14
        &ett_bthci_acl,
655
14
    };
656
657
14
    static ei_register_info ei[] = {
658
14
        { &ei_invalid_session, { "bthci_acl.invalid_session", PI_PROTOCOL,  PI_ERROR, "Frame is out of any \"connection handle\" session", EXPFILL }},
659
14
        { &ei_length_bad,      { "bthci_acl.length.bad",      PI_MALFORMED, PI_WARN, "Length too short", EXPFILL }},
660
14
    };
661
662
    /* Register the protocol name and description */
663
14
    proto_bthci_acl = proto_register_protocol("Bluetooth HCI ACL Packet", "HCI_ACL", "bthci_acl");
664
14
    bthci_acl_handle = register_dissector("bthci_acl", dissect_bthci_acl, proto_bthci_acl);
665
666
    /* Required function calls to register the header fields and subtrees used */
667
14
    proto_register_field_array(proto_bthci_acl, hf, array_length(hf));
668
14
    proto_register_subtree_array(ett, array_length(ett));
669
670
14
    bthci_acl_expert_module = expert_register_protocol(proto_bthci_acl);
671
14
    expert_register_field_array(bthci_acl_expert_module, ei, array_length(ei));
672
673
    /* Register configuration preferences */
674
14
    bthci_acl_module = prefs_register_protocol_subtree("Bluetooth", proto_bthci_acl, NULL);
675
14
    prefs_register_bool_preference(bthci_acl_module, "hci_acl_reassembly",
676
14
        "Reassemble ACL Fragments",
677
14
        "Whether the ACL dissector should reassemble fragmented PDUs",
678
14
        &acl_reassembly);
679
680
14
    chandle_tree = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
681
14
}
682
683
684
void
685
proto_reg_handoff_bthci_acl(void)
686
14
{
687
14
    dissector_add_uint("hci_h4.type", HCI_H4_TYPE_ACL, bthci_acl_handle);
688
14
    dissector_add_uint("hci_h1.type", BTHCI_CHANNEL_ACL, bthci_acl_handle);
689
690
14
    btl2cap_handle = find_dissector_add_dependency("btl2cap", proto_bthci_acl);
691
14
}
692
693
/*
694
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
695
 *
696
 * Local variables:
697
 * c-basic-offset: 4
698
 * tab-width: 8
699
 * indent-tabs-mode: nil
700
 * End:
701
 *
702
 * vi: set shiftwidth=4 tabstop=8 expandtab:
703
 * :indentSize=4:tabSize=8:noTabs=true:
704
 */