Coverage Report

Created: 2025-08-04 07:15

/src/wireshark/epan/dissectors/packet-btmesh-beacon.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-btmesh-beacon.c
2
 * Routines for Bluetooth mesh PB-ADV dissection
3
 *
4
 * Copyright 2019, Piotr Winiarczyk <wino45@gmail.com>
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
 * Ref: Mesh Profile v1.0
13
 * https://www.bluetooth.com/specifications/mesh-specifications
14
 */
15
16
#include "config.h"
17
18
#include <epan/packet.h>
19
#include <epan/prefs.h>
20
#include <epan/expert.h>
21
#include <epan/tfs.h>
22
23
#include "packet-btmesh.h"
24
25
0
#define BEACON_UNPROVISION 0x00
26
0
#define BEACON_SECURE      0x01
27
28
void proto_register_btmesh_beacon(void);
29
30
static int proto_btmesh_beacon;
31
32
static int hf_btmesh_beacon_type;
33
static int hf_btmesh_beacon_uuid;
34
static int hf_btmesh_beacon_oob;
35
static int hf_btmesh_beacon_oob_other;
36
static int hf_btmesh_beacon_oob_electronic;
37
static int hf_btmesh_beacon_oob_2d_code;
38
static int hf_btmesh_beacon_oob_bar_code;
39
static int hf_btmesh_beacon_oob_nfc;
40
static int hf_btmesh_beacon_oob_number;
41
static int hf_btmesh_beacon_oob_string;
42
static int hf_btmesh_beacon_oob_rfu;
43
static int hf_btmesh_beacon_oob_on_box;
44
static int hf_btmesh_beacon_oob_inside_box;
45
static int hf_btmesh_beacon_oob_on_paper;
46
static int hf_btmesh_beacon_oob_inside_manual;
47
static int hf_btmesh_beacon_oob_on_device;
48
static int hf_btmesh_beacon_uri_hash;
49
static int hf_btmesh_beacon_flags;
50
static int hf_btmesh_beacon_flags_key_refresh;
51
static int hf_btmesh_beacon_flags_iv_update;
52
static int hf_btmesh_beacon_flags_rfu;
53
static int hf_btmesh_beacon_network_id;
54
static int hf_btmesh_beacon_ivindex;
55
//TODO: check authentication value
56
static int hf_btmesh_beacon_authentication_value;
57
static int hf_btmesh_beacon_unknown_data;
58
59
static int ett_btmesh_beacon;
60
static int ett_btmesh_beacon_oob;
61
static int ett_btmesh_beacon_flags;
62
63
static expert_field ei_btmesh_beacon_unknown_beacon_type;
64
static expert_field ei_btmesh_beacon_unknown_payload;
65
static expert_field ei_btmesh_beacon_rfu_not_zero;
66
67
static const value_string btmesh_beacon_type[] = {
68
    { 0, "Unprovisioned Device Beacon" },
69
    { 1, "Secure Network Beacon" },
70
    { 0, NULL }
71
};
72
73
static const true_false_string flags_key_refresh = {
74
  "Key Refresh in progress",
75
  "Key Refresh not in progress"
76
};
77
78
static const true_false_string flags_iv_update = {
79
  "IV Update active",
80
  "Normal operation"
81
};
82
83
static int
84
dissect_btmesh_beacon_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
85
10
{
86
87
10
    proto_item *item, *oob_item, *flags_item;
88
10
    proto_tree *sub_tree, *oob_tree, *flags_tree;
89
10
    unsigned offset = 0;
90
10
    unsigned data_size = 0;
91
10
    btle_mesh_transport_ctx_t *tr_ctx;
92
10
    btle_mesh_transport_ctx_t dummy_ctx = {E_BTMESH_TR_UNKNOWN, false, 0};
93
10
    uint16_t rfu_bits16;
94
10
    uint8_t rfu_bits8;
95
96
10
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "BT Mesh Beacon");
97
98
10
    if (data == NULL) {
99
10
        tr_ctx = &dummy_ctx;
100
10
    } else {
101
0
        tr_ctx = (btle_mesh_transport_ctx_t *) data;
102
0
    }
103
104
10
    item = proto_tree_add_item(tree, proto_btmesh_beacon, tvb, offset, -1, ENC_NA);
105
10
    sub_tree = proto_item_add_subtree(item, ett_btmesh_beacon);
106
107
10
    uint8_t beacon_type = tvb_get_uint8(tvb, offset);
108
10
    proto_tree_add_item(sub_tree, hf_btmesh_beacon_type, tvb, offset, 1, ENC_NA);
109
10
    offset += 1;
110
111
10
    col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(beacon_type, btmesh_beacon_type, "Unknown Beacon Type"));
112
10
    if (tr_ctx->fragmented) {
113
0
        switch (tr_ctx->transport) {
114
0
            case E_BTMESH_TR_PROXY:
115
0
                col_append_str(pinfo->cinfo, COL_INFO," (Last Segment)");
116
117
0
            break;
118
0
            default:
119
            //No default is needed since this is an additional information only
120
121
0
            break;
122
0
        }
123
0
    }
124
125
10
    switch(beacon_type) {
126
0
        case BEACON_UNPROVISION:
127
0
            proto_tree_add_item(sub_tree, hf_btmesh_beacon_uuid, tvb, offset, 16, ENC_BIG_ENDIAN);
128
0
            offset += 16;
129
130
0
            oob_item = proto_tree_add_item(sub_tree, hf_btmesh_beacon_oob, tvb, offset, 2, ENC_BIG_ENDIAN);
131
0
            oob_tree = proto_item_add_subtree(oob_item, ett_btmesh_beacon_oob);
132
133
0
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_other, tvb, offset, 2, ENC_BIG_ENDIAN);
134
0
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_electronic, tvb, offset, 2, ENC_BIG_ENDIAN);
135
0
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_2d_code, tvb, offset, 2, ENC_BIG_ENDIAN);
136
0
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_bar_code, tvb, offset, 2, ENC_BIG_ENDIAN);
137
0
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_nfc, tvb, offset, 2, ENC_BIG_ENDIAN);
138
0
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_number, tvb, offset, 2, ENC_BIG_ENDIAN);
139
0
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_string, tvb, offset, 2, ENC_BIG_ENDIAN);
140
0
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_rfu, tvb, offset, 2, ENC_BIG_ENDIAN);
141
0
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_on_box, tvb, offset, 2, ENC_BIG_ENDIAN);
142
0
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_inside_box, tvb, offset, 2, ENC_BIG_ENDIAN);
143
0
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_on_paper, tvb, offset, 2, ENC_BIG_ENDIAN);
144
0
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_inside_manual, tvb, offset, 2, ENC_BIG_ENDIAN);
145
0
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_on_device, tvb, offset, 2, ENC_BIG_ENDIAN);
146
0
            rfu_bits16 = (tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN) & 0x0780) >> 7;
147
0
            if (rfu_bits16 != 0) {
148
                //RFU bits should be 0
149
0
                proto_tree_add_expert(oob_tree, pinfo, &ei_btmesh_beacon_rfu_not_zero, tvb, offset, -1);
150
0
            }
151
0
            offset += 2;
152
153
0
            data_size = tvb_reported_length(tvb);
154
0
            if (data_size == offset + 4 ) {
155
0
                proto_tree_add_item(sub_tree, hf_btmesh_beacon_uri_hash, tvb, offset, 4, ENC_NA);
156
0
                offset += 4;
157
0
            }
158
            //Wrong size handled outside switch/case
159
160
0
        break;
161
0
        case BEACON_SECURE:
162
0
            flags_item = proto_tree_add_item(sub_tree, hf_btmesh_beacon_flags, tvb, offset, 1, ENC_NA);
163
0
            flags_tree = proto_item_add_subtree(flags_item, ett_btmesh_beacon_flags);
164
0
            proto_tree_add_item(flags_tree, hf_btmesh_beacon_flags_key_refresh, tvb, offset, 1, ENC_NA);
165
0
            proto_tree_add_item(flags_tree, hf_btmesh_beacon_flags_iv_update, tvb, offset, 1, ENC_NA);
166
0
            proto_tree_add_item(flags_tree, hf_btmesh_beacon_flags_rfu, tvb, offset, 1, ENC_NA);
167
0
            rfu_bits8 = tvb_get_uint8(tvb, offset) >> 2;
168
0
            if (rfu_bits8 != 0) {
169
                //RFU bits should be 0
170
0
                proto_tree_add_expert(flags_tree, pinfo, &ei_btmesh_beacon_rfu_not_zero, tvb, offset, -1);
171
0
            }
172
0
            offset += 1;
173
0
            proto_tree_add_item(sub_tree, hf_btmesh_beacon_network_id, tvb, offset, 8, ENC_NA);
174
0
            offset += 8;
175
0
            proto_tree_add_item(sub_tree, hf_btmesh_beacon_ivindex, tvb, offset, 4, ENC_BIG_ENDIAN);
176
0
            offset += 4;
177
0
            proto_tree_add_item(sub_tree, hf_btmesh_beacon_authentication_value, tvb, offset, 8, ENC_NA);
178
0
            offset += 8;
179
0
        break;
180
10
        default:
181
            //Unknown mesh beacon type, display data and flag it
182
10
            proto_tree_add_item(sub_tree, hf_btmesh_beacon_unknown_data, tvb, offset, -1, ENC_NA);
183
10
            proto_tree_add_expert(sub_tree, pinfo, &ei_btmesh_beacon_unknown_beacon_type, tvb, offset, -1);
184
10
            offset += tvb_captured_length_remaining(tvb, offset);
185
10
        break;
186
10
    }
187
    //There is still some data but all data should be already disssected
188
10
    if (tvb_captured_length_remaining(tvb, offset) != 0) {
189
0
        proto_tree_add_expert(sub_tree, pinfo, &ei_btmesh_beacon_unknown_payload, tvb, offset, -1);
190
0
    }
191
192
10
    return tvb_reported_length(tvb);
193
10
}
194
195
void
196
proto_register_btmesh_beacon(void)
197
14
{
198
14
    static hf_register_info hf[] = {
199
14
        { &hf_btmesh_beacon_type,
200
14
            { "Type", "beacon.type",
201
14
                FT_UINT8, BASE_DEC, VALS(btmesh_beacon_type), 0x0,
202
14
                NULL, HFILL }
203
14
        },
204
14
        { &hf_btmesh_beacon_uuid,
205
14
            { "Device UUID", "beacon.uuid",
206
14
                FT_GUID, BASE_NONE, NULL, 0x0,
207
14
                NULL, HFILL }
208
14
        },
209
14
        { &hf_btmesh_beacon_oob,
210
14
            { "OOB Information", "beacon.oob",
211
14
                FT_UINT16, BASE_HEX, NULL, 0x0,
212
14
                NULL, HFILL }
213
14
        },
214
14
        { &hf_btmesh_beacon_oob_other,
215
14
            { "Other", "beacon.oob.other",
216
14
                FT_BOOLEAN, 16, TFS(&tfs_available_not_available), 0x0001,
217
14
                NULL, HFILL }
218
14
        },
219
14
       { &hf_btmesh_beacon_oob_electronic,
220
14
            { "Electronic / URI", "beacon.oob.electronic",
221
14
                FT_BOOLEAN, 16, TFS(&tfs_available_not_available), 0x0002,
222
14
                NULL, HFILL }
223
14
        },
224
14
       { &hf_btmesh_beacon_oob_2d_code,
225
14
            { "2D machine-readable code", "beacon.oob.2d_code",
226
14
                FT_BOOLEAN, 16, TFS(&tfs_available_not_available), 0x0004,
227
14
                NULL, HFILL }
228
14
        },
229
14
       { &hf_btmesh_beacon_oob_bar_code,
230
14
            { "Bar code", "beacon.oob.bar_code",
231
14
                FT_BOOLEAN, 16, TFS(&tfs_available_not_available), 0x0008,
232
14
                NULL, HFILL }
233
14
        },
234
14
       { &hf_btmesh_beacon_oob_nfc,
235
14
            { "Near Field Communication (NFC)", "beacon.oob.nfc",
236
14
                FT_BOOLEAN, 16, TFS(&tfs_available_not_available), 0x0010,
237
14
                NULL, HFILL }
238
14
        },
239
14
       { &hf_btmesh_beacon_oob_number,
240
14
            { "Number", "beacon.oob.number",
241
14
                FT_BOOLEAN, 16, TFS(&tfs_available_not_available), 0x0020,
242
14
                NULL, HFILL }
243
14
        },
244
14
       { &hf_btmesh_beacon_oob_string,
245
14
            { "String", "beacon.oob.string",
246
14
                FT_BOOLEAN, 16, TFS(&tfs_available_not_available), 0x0040,
247
14
                NULL, HFILL }
248
14
        },
249
14
       { &hf_btmesh_beacon_oob_rfu,
250
14
            { "Reserved for Future Use", "beacon.oob.rfu",
251
14
                FT_UINT16, BASE_DEC, NULL, 0x0780,
252
14
                NULL, HFILL }
253
14
        },
254
14
       { &hf_btmesh_beacon_oob_on_box,
255
14
            { "On box", "beacon.oob.on_box",
256
14
                FT_BOOLEAN, 16, TFS(&tfs_available_not_available), 0x0800,
257
14
                NULL, HFILL }
258
14
        },
259
14
       { &hf_btmesh_beacon_oob_inside_box,
260
14
            { "Inside box", "beacon.oob.inside_box",
261
14
                FT_BOOLEAN, 16, TFS(&tfs_available_not_available), 0x1000,
262
14
                NULL, HFILL }
263
14
        },
264
14
       { &hf_btmesh_beacon_oob_on_paper,
265
14
            { "On piece of paper", "beacon.oob.on_paper",
266
14
                FT_BOOLEAN, 16, TFS(&tfs_available_not_available), 0x2000,
267
14
                NULL, HFILL }
268
14
        },
269
14
       { &hf_btmesh_beacon_oob_inside_manual,
270
14
            { "Inside manual", "beacon.oob.inside_manual",
271
14
                FT_BOOLEAN, 16, TFS(&tfs_available_not_available), 0x4000,
272
14
                NULL, HFILL }
273
14
        },
274
14
       { &hf_btmesh_beacon_oob_on_device,
275
14
            { "On device", "beacon.oob.on_device",
276
14
                FT_BOOLEAN, 16, TFS(&tfs_available_not_available), 0x8000,
277
14
                NULL, HFILL }
278
14
        },
279
14
        { &hf_btmesh_beacon_uri_hash,
280
14
            { "URI Hash", "beacon.uri_hash",
281
14
                FT_BYTES, BASE_NONE, NULL, 0x0,
282
14
                NULL, HFILL }
283
14
        },
284
14
        { &hf_btmesh_beacon_flags,
285
14
            { "Flags", "beacon.flags",
286
14
                FT_UINT8, BASE_HEX, NULL, 0x0,
287
14
                NULL, HFILL }
288
14
        },
289
14
       { &hf_btmesh_beacon_flags_key_refresh,
290
14
            { "Key Refresh Flag", "beacon.flags.key_refresh",
291
14
                FT_BOOLEAN, 8, TFS(&flags_key_refresh), 0x01,
292
14
                NULL, HFILL }
293
14
        },
294
14
       { &hf_btmesh_beacon_flags_iv_update,
295
14
            { "IV Update Flag", "beacon.flags.iv_update",
296
14
                FT_BOOLEAN, 8, TFS(&flags_iv_update), 0x02,
297
14
                NULL, HFILL }
298
14
        },
299
14
       { &hf_btmesh_beacon_flags_rfu,
300
14
            { "Reserved for Future Use", "beacon.flags.rfu",
301
14
                FT_UINT8, BASE_DEC, NULL, 0xFC,
302
14
                NULL, HFILL }
303
14
        },
304
14
       { &hf_btmesh_beacon_network_id,
305
14
            { "Network ID", "beacon.network_id",
306
14
                FT_BYTES, BASE_NONE, NULL, 0x0,
307
14
                NULL, HFILL }
308
14
        },
309
14
        { &hf_btmesh_beacon_ivindex,
310
14
            { "IV Index", "beacon.ivindex",
311
14
                FT_UINT32, BASE_DEC, NULL, 0x0,
312
14
                NULL, HFILL }
313
14
        },
314
14
        { &hf_btmesh_beacon_authentication_value,
315
14
            { "Authentication Value", "beacon.authentication_value",
316
14
                FT_BYTES, BASE_NONE, NULL, 0x0,
317
14
                NULL, HFILL }
318
14
        },
319
14
        { &hf_btmesh_beacon_unknown_data,
320
14
            { "Unknown Data", "beacon.unknown_data",
321
14
                FT_BYTES, BASE_NONE, NULL, 0x0,
322
14
                NULL, HFILL }
323
14
        },
324
14
    };
325
326
14
    static int *ett[] = {
327
14
        &ett_btmesh_beacon,
328
14
        &ett_btmesh_beacon_oob,
329
14
        &ett_btmesh_beacon_flags,
330
14
    };
331
332
14
    static ei_register_info ei[] = {
333
14
        { &ei_btmesh_beacon_unknown_beacon_type,{ "beacon.unknown_beacon_type", PI_PROTOCOL, PI_ERROR, "Unknown Beacon Type", EXPFILL } },
334
14
        { &ei_btmesh_beacon_unknown_payload,{ "beacon.unknown_payload", PI_PROTOCOL, PI_ERROR, "Unknown Payload", EXPFILL } },
335
14
        { &ei_btmesh_beacon_rfu_not_zero,{ "beacon.rfu_not_zero", PI_PROTOCOL, PI_WARN, "Reserved for Future Use value not equal to 0", EXPFILL } },
336
14
    };
337
338
14
    expert_module_t* expert_btmesh_beacon;
339
340
14
    proto_btmesh_beacon = proto_register_protocol("Bluetooth Mesh Beacon", "BT Mesh beacon", "beacon");
341
342
14
    proto_register_field_array(proto_btmesh_beacon, hf, array_length(hf));
343
14
    proto_register_subtree_array(ett, array_length(ett));
344
345
14
    expert_btmesh_beacon = expert_register_protocol(proto_btmesh_beacon);
346
14
    expert_register_field_array(expert_btmesh_beacon, ei, array_length(ei));
347
348
14
    prefs_register_protocol_subtree("Bluetooth", proto_btmesh_beacon, NULL);
349
14
    register_dissector("btmesh.beacon", dissect_btmesh_beacon_msg, proto_btmesh_beacon);
350
14
}
351
352
/*
353
 * Editor modelines
354
 *
355
 * Local Variables:
356
 * c-basic-offset: 4
357
 * tab-width: 8
358
 * indent-tabs-mode: nil
359
 * End:
360
 *
361
 * ex: set shiftwidth=4 tabstop=8 expandtab:
362
 * :indentSize=4:tabSize=8:noTabs=true:
363
 */