Coverage Report

Created: 2026-09-28 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-btmesh-beacon.c
Line
Count
Source
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
1
#define BEACON_UNPROVISION 0x00
26
1
#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
12
{
86
87
12
    proto_item *item, *oob_item, *flags_item;
88
12
    proto_tree *sub_tree, *oob_tree, *flags_tree;
89
12
    unsigned offset = 0;
90
12
    unsigned data_size = 0;
91
12
    btle_mesh_transport_ctx_t *tr_ctx;
92
12
    btle_mesh_transport_ctx_t dummy_ctx = {E_BTMESH_TR_UNKNOWN, false, 0};
93
12
    uint16_t rfu_bits16;
94
12
    uint8_t rfu_bits8;
95
96
12
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "BT Mesh Beacon");
97
98
12
    if (data == NULL) {
99
12
        tr_ctx = &dummy_ctx;
100
12
    } else {
101
0
        tr_ctx = (btle_mesh_transport_ctx_t *) data;
102
0
    }
103
104
12
    item = proto_tree_add_item(tree, proto_btmesh_beacon, tvb, offset, -1, ENC_NA);
105
12
    sub_tree = proto_item_add_subtree(item, ett_btmesh_beacon);
106
107
12
    uint8_t beacon_type = tvb_get_uint8(tvb, offset);
108
12
    proto_tree_add_item(sub_tree, hf_btmesh_beacon_type, tvb, offset, 1, ENC_NA);
109
12
    offset += 1;
110
111
12
    col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(beacon_type, btmesh_beacon_type, "Unknown Beacon Type"));
112
12
    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
12
    switch(beacon_type) {
126
1
        case BEACON_UNPROVISION:
127
1
            proto_tree_add_item(sub_tree, hf_btmesh_beacon_uuid, tvb, offset, 16, ENC_BIG_ENDIAN);
128
1
            offset += 16;
129
130
1
            oob_item = proto_tree_add_item(sub_tree, hf_btmesh_beacon_oob, tvb, offset, 2, ENC_BIG_ENDIAN);
131
1
            oob_tree = proto_item_add_subtree(oob_item, ett_btmesh_beacon_oob);
132
133
1
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_other, tvb, offset, 2, ENC_BIG_ENDIAN);
134
1
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_electronic, tvb, offset, 2, ENC_BIG_ENDIAN);
135
1
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_2d_code, tvb, offset, 2, ENC_BIG_ENDIAN);
136
1
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_bar_code, tvb, offset, 2, ENC_BIG_ENDIAN);
137
1
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_nfc, tvb, offset, 2, ENC_BIG_ENDIAN);
138
1
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_number, tvb, offset, 2, ENC_BIG_ENDIAN);
139
1
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_string, tvb, offset, 2, ENC_BIG_ENDIAN);
140
1
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_rfu, tvb, offset, 2, ENC_BIG_ENDIAN);
141
1
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_on_box, tvb, offset, 2, ENC_BIG_ENDIAN);
142
1
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_inside_box, tvb, offset, 2, ENC_BIG_ENDIAN);
143
1
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_on_paper, tvb, offset, 2, ENC_BIG_ENDIAN);
144
1
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_inside_manual, tvb, offset, 2, ENC_BIG_ENDIAN);
145
1
            proto_tree_add_item(oob_tree, hf_btmesh_beacon_oob_on_device, tvb, offset, 2, ENC_BIG_ENDIAN);
146
1
            rfu_bits16 = (tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN) & 0x0780) >> 7;
147
1
            if (rfu_bits16 != 0) {
148
                //RFU bits should be 0
149
1
                proto_tree_add_expert_remaining(oob_tree, pinfo, &ei_btmesh_beacon_rfu_not_zero, tvb, offset);
150
1
            }
151
1
            offset += 2;
152
153
1
            data_size = tvb_reported_length(tvb);
154
1
            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
1
        break;
161
1
        case BEACON_SECURE:
162
1
            flags_item = proto_tree_add_item(sub_tree, hf_btmesh_beacon_flags, tvb, offset, 1, ENC_NA);
163
1
            flags_tree = proto_item_add_subtree(flags_item, ett_btmesh_beacon_flags);
164
1
            proto_tree_add_item(flags_tree, hf_btmesh_beacon_flags_key_refresh, tvb, offset, 1, ENC_NA);
165
1
            proto_tree_add_item(flags_tree, hf_btmesh_beacon_flags_iv_update, tvb, offset, 1, ENC_NA);
166
1
            proto_tree_add_item(flags_tree, hf_btmesh_beacon_flags_rfu, tvb, offset, 1, ENC_NA);
167
1
            rfu_bits8 = tvb_get_uint8(tvb, offset) >> 2;
168
1
            if (rfu_bits8 != 0) {
169
                //RFU bits should be 0
170
1
                proto_tree_add_expert_remaining(flags_tree, pinfo, &ei_btmesh_beacon_rfu_not_zero, tvb, offset);
171
1
            }
172
1
            offset += 1;
173
1
            proto_tree_add_item(sub_tree, hf_btmesh_beacon_network_id, tvb, offset, 8, ENC_NA);
174
1
            offset += 8;
175
1
            proto_tree_add_item(sub_tree, hf_btmesh_beacon_ivindex, tvb, offset, 4, ENC_BIG_ENDIAN);
176
1
            offset += 4;
177
1
            proto_tree_add_item(sub_tree, hf_btmesh_beacon_authentication_value, tvb, offset, 8, ENC_NA);
178
1
            offset += 8;
179
1
        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_remaining(sub_tree, pinfo, &ei_btmesh_beacon_unknown_beacon_type, tvb, offset);
184
10
            offset += tvb_captured_length_remaining(tvb, offset);
185
10
        break;
186
12
    }
187
    //There is still some data but all data should be already disssected
188
12
    if (tvb_captured_length_remaining(tvb, offset) != 0) {
189
2
        proto_tree_add_expert_remaining(sub_tree, pinfo, &ei_btmesh_beacon_unknown_payload, tvb, offset);
190
2
    }
191
192
12
    return tvb_reported_length(tvb);
193
12
}
194
195
void
196
proto_register_btmesh_beacon(void)
197
16
{
198
16
    static hf_register_info hf[] = {
199
16
        { &hf_btmesh_beacon_type,
200
16
            { "Type", "beacon.type",
201
16
                FT_UINT8, BASE_DEC, VALS(btmesh_beacon_type), 0x0,
202
16
                NULL, HFILL }
203
16
        },
204
16
        { &hf_btmesh_beacon_uuid,
205
16
            { "Device UUID", "beacon.uuid",
206
16
                FT_GUID, BASE_NONE, NULL, 0x0,
207
16
                NULL, HFILL }
208
16
        },
209
16
        { &hf_btmesh_beacon_oob,
210
16
            { "OOB Information", "beacon.oob",
211
16
                FT_UINT16, BASE_HEX, NULL, 0x0,
212
16
                NULL, HFILL }
213
16
        },
214
16
        { &hf_btmesh_beacon_oob_other,
215
16
            { "Other", "beacon.oob.other",
216
16
                FT_BOOLEAN, 16, TFS(&tfs_available_not_available), 0x0001,
217
16
                NULL, HFILL }
218
16
        },
219
16
       { &hf_btmesh_beacon_oob_electronic,
220
16
            { "Electronic / URI", "beacon.oob.electronic",
221
16
                FT_BOOLEAN, 16, TFS(&tfs_available_not_available), 0x0002,
222
16
                NULL, HFILL }
223
16
        },
224
16
       { &hf_btmesh_beacon_oob_2d_code,
225
16
            { "2D machine-readable code", "beacon.oob.2d_code",
226
16
                FT_BOOLEAN, 16, TFS(&tfs_available_not_available), 0x0004,
227
16
                NULL, HFILL }
228
16
        },
229
16
       { &hf_btmesh_beacon_oob_bar_code,
230
16
            { "Bar code", "beacon.oob.bar_code",
231
16
                FT_BOOLEAN, 16, TFS(&tfs_available_not_available), 0x0008,
232
16
                NULL, HFILL }
233
16
        },
234
16
       { &hf_btmesh_beacon_oob_nfc,
235
16
            { "Near Field Communication (NFC)", "beacon.oob.nfc",
236
16
                FT_BOOLEAN, 16, TFS(&tfs_available_not_available), 0x0010,
237
16
                NULL, HFILL }
238
16
        },
239
16
       { &hf_btmesh_beacon_oob_number,
240
16
            { "Number", "beacon.oob.number",
241
16
                FT_BOOLEAN, 16, TFS(&tfs_available_not_available), 0x0020,
242
16
                NULL, HFILL }
243
16
        },
244
16
       { &hf_btmesh_beacon_oob_string,
245
16
            { "String", "beacon.oob.string",
246
16
                FT_BOOLEAN, 16, TFS(&tfs_available_not_available), 0x0040,
247
16
                NULL, HFILL }
248
16
        },
249
16
       { &hf_btmesh_beacon_oob_rfu,
250
16
            { "Reserved for Future Use", "beacon.oob.rfu",
251
16
                FT_UINT16, BASE_DEC, NULL, 0x0780,
252
16
                NULL, HFILL }
253
16
        },
254
16
       { &hf_btmesh_beacon_oob_on_box,
255
16
            { "On box", "beacon.oob.on_box",
256
16
                FT_BOOLEAN, 16, TFS(&tfs_available_not_available), 0x0800,
257
16
                NULL, HFILL }
258
16
        },
259
16
       { &hf_btmesh_beacon_oob_inside_box,
260
16
            { "Inside box", "beacon.oob.inside_box",
261
16
                FT_BOOLEAN, 16, TFS(&tfs_available_not_available), 0x1000,
262
16
                NULL, HFILL }
263
16
        },
264
16
       { &hf_btmesh_beacon_oob_on_paper,
265
16
            { "On piece of paper", "beacon.oob.on_paper",
266
16
                FT_BOOLEAN, 16, TFS(&tfs_available_not_available), 0x2000,
267
16
                NULL, HFILL }
268
16
        },
269
16
       { &hf_btmesh_beacon_oob_inside_manual,
270
16
            { "Inside manual", "beacon.oob.inside_manual",
271
16
                FT_BOOLEAN, 16, TFS(&tfs_available_not_available), 0x4000,
272
16
                NULL, HFILL }
273
16
        },
274
16
       { &hf_btmesh_beacon_oob_on_device,
275
16
            { "On device", "beacon.oob.on_device",
276
16
                FT_BOOLEAN, 16, TFS(&tfs_available_not_available), 0x8000,
277
16
                NULL, HFILL }
278
16
        },
279
16
        { &hf_btmesh_beacon_uri_hash,
280
16
            { "URI Hash", "beacon.uri_hash",
281
16
                FT_BYTES, BASE_NONE, NULL, 0x0,
282
16
                NULL, HFILL }
283
16
        },
284
16
        { &hf_btmesh_beacon_flags,
285
16
            { "Flags", "beacon.flags",
286
16
                FT_UINT8, BASE_HEX, NULL, 0x0,
287
16
                NULL, HFILL }
288
16
        },
289
16
       { &hf_btmesh_beacon_flags_key_refresh,
290
16
            { "Key Refresh Flag", "beacon.flags.key_refresh",
291
16
                FT_BOOLEAN, 8, TFS(&flags_key_refresh), 0x01,
292
16
                NULL, HFILL }
293
16
        },
294
16
       { &hf_btmesh_beacon_flags_iv_update,
295
16
            { "IV Update Flag", "beacon.flags.iv_update",
296
16
                FT_BOOLEAN, 8, TFS(&flags_iv_update), 0x02,
297
16
                NULL, HFILL }
298
16
        },
299
16
       { &hf_btmesh_beacon_flags_rfu,
300
16
            { "Reserved for Future Use", "beacon.flags.rfu",
301
16
                FT_UINT8, BASE_DEC, NULL, 0xFC,
302
16
                NULL, HFILL }
303
16
        },
304
16
       { &hf_btmesh_beacon_network_id,
305
16
            { "Network ID", "beacon.network_id",
306
16
                FT_BYTES, BASE_NONE, NULL, 0x0,
307
16
                NULL, HFILL }
308
16
        },
309
16
        { &hf_btmesh_beacon_ivindex,
310
16
            { "IV Index", "beacon.ivindex",
311
16
                FT_UINT32, BASE_DEC, NULL, 0x0,
312
16
                NULL, HFILL }
313
16
        },
314
16
        { &hf_btmesh_beacon_authentication_value,
315
16
            { "Authentication Value", "beacon.authentication_value",
316
16
                FT_BYTES, BASE_NONE, NULL, 0x0,
317
16
                NULL, HFILL }
318
16
        },
319
16
        { &hf_btmesh_beacon_unknown_data,
320
16
            { "Unknown Data", "beacon.unknown_data",
321
16
                FT_BYTES, BASE_NONE, NULL, 0x0,
322
16
                NULL, HFILL }
323
16
        },
324
16
    };
325
326
16
    static int *ett[] = {
327
16
        &ett_btmesh_beacon,
328
16
        &ett_btmesh_beacon_oob,
329
16
        &ett_btmesh_beacon_flags,
330
16
    };
331
332
16
    static ei_register_info ei[] = {
333
16
        { &ei_btmesh_beacon_unknown_beacon_type,{ "beacon.unknown_beacon_type", PI_PROTOCOL, PI_ERROR, "Unknown Beacon Type", EXPFILL } },
334
16
        { &ei_btmesh_beacon_unknown_payload,{ "beacon.unknown_payload", PI_PROTOCOL, PI_ERROR, "Unknown Payload", EXPFILL } },
335
16
        { &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
16
    };
337
338
16
    expert_module_t* expert_btmesh_beacon;
339
340
16
    proto_btmesh_beacon = proto_register_protocol("Bluetooth Mesh Beacon", "BT Mesh beacon", "beacon");
341
342
16
    proto_register_field_array(proto_btmesh_beacon, hf, array_length(hf));
343
16
    proto_register_subtree_array(ett, array_length(ett));
344
345
16
    expert_btmesh_beacon = expert_register_protocol(proto_btmesh_beacon);
346
16
    expert_register_field_array(expert_btmesh_beacon, ei, array_length(ei));
347
348
    prefs_register_protocol_subtree("Bluetooth", proto_btmesh_beacon, NULL);
349
16
    register_dissector("btmesh.beacon", dissect_btmesh_beacon_msg, proto_btmesh_beacon);
350
16
}
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
 */