Coverage Report

Created: 2026-06-30 07:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-btmesh-pbadv.c
Line
Count
Source
1
/* packet-btmesh-pbadv.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/reassemble.h>
21
#include <epan/expert.h>
22
23
#include "packet-btmesh.h"
24
25
21
#define BTMESH_PB_ADV_NOT_USED 0
26
27
9
#define TRANSACTION_START           0x00
28
18
#define TRANSACTION_ACKNOWLEDGMENT  0x01
29
9
#define TRANSACTION_CONTINUATION    0x02
30
1
#define PROVISIONING_BEARER_CONTROL 0x03
31
32
0
#define LINK_OPEN  0x00
33
0
#define LINK_ACK   0x01
34
0
#define LINK_CLOSE 0x02
35
36
void proto_register_btmesh_pbadv(void);
37
void proto_reg_handoff_btmesh_pbadv(void);
38
39
static int proto_btmesh_pbadv;
40
41
static dissector_handle_t btmesh_provisioning_handle;
42
43
static int hf_btmesh_pbadv_linkid;
44
static int hf_btmesh_pbadv_trnumber;
45
46
static int hf_btmesh_generic_provisioning_control_format;
47
static int hf_btmesh_gpcf_segn;
48
static int hf_btmesh_gpcf_total_length;
49
//TODO - check FCS
50
static int hf_btmesh_gpcf_fcs;
51
static int hf_btmesh_gpcf_padding;
52
static int hf_btmesh_gpcf_segment_index;
53
static int hf_btmesh_gpcf_bearer_opcode;
54
static int hf_btmesh_gpcf_bearer_opcode_device_UUID;
55
static int hf_btmesh_gpcf_bearer_opcode_reason;
56
static int hf_btmesh_gpcf_bearer_unknown_data;
57
58
static int hf_btmesh_gpp_payload;
59
static int hf_btmesh_gpp_payload_fragment;
60
static int hf_btmesh_gpp_fragments;
61
static int hf_btmesh_gpp_fragment;
62
static int hf_btmesh_gpp_fragment_overlap;
63
static int hf_btmesh_gpp_fragment_overlap_conflict;
64
static int hf_btmesh_gpp_fragment_multiple_tails;
65
static int hf_btmesh_gpp_fragment_too_long_fragment;
66
static int hf_btmesh_gpp_fragment_error;
67
static int hf_btmesh_gpp_fragment_count;
68
static int hf_btmesh_gpp_reassembled_length;
69
70
static int ett_btmesh_pbadv;
71
static int ett_btmesh_generic_provisioning;
72
static int ett_btmesh_gpp_fragments;
73
static int ett_btmesh_gpp_fragment;
74
75
static expert_field ei_btmesh_gpcf_unknown_opcode;
76
static expert_field ei_btmesh_gpcf_unknown_payload;
77
78
static const fragment_items btmesh_gpp_frag_items = {
79
    &ett_btmesh_gpp_fragments,
80
    &ett_btmesh_gpp_fragment,
81
82
    &hf_btmesh_gpp_fragments,
83
    &hf_btmesh_gpp_fragment,
84
    &hf_btmesh_gpp_fragment_overlap,
85
    &hf_btmesh_gpp_fragment_overlap_conflict,
86
    &hf_btmesh_gpp_fragment_multiple_tails,
87
    &hf_btmesh_gpp_fragment_too_long_fragment,
88
    &hf_btmesh_gpp_fragment_error,
89
    &hf_btmesh_gpp_fragment_count,
90
    NULL,
91
    &hf_btmesh_gpp_reassembled_length,
92
    /* Reassembled data field */
93
    NULL,
94
    "fragments"
95
};
96
97
static const value_string btmesh_generic_provisioning_control_format[] = {
98
    { 0, "Transaction Start" },
99
    { 1, "Transaction Acknowledgment" },
100
    { 2, "Transaction Continuation" },
101
    { 3, "Provisioning Bearer Control" },
102
    { 0, NULL }
103
};
104
105
static const value_string btmesh_gpcf_bearer_opcode_format[] = {
106
    { 0, "Link Open" },
107
    { 1, "Link ACK" },
108
    { 2, "Link Close" },
109
    { 0, NULL }
110
};
111
112
static const value_string btmesh_gpcf_bearer_opcode_reason_format[] = {
113
    { 0, "Success" },
114
    { 1, "Timeout" },
115
    { 2, "Fail" },
116
    { 0, NULL }
117
};
118
119
/* needed for packet reassembly */
120
static reassembly_table pbadv_reassembly_table;
121
122
typedef struct _pbadv_fragment_key {
123
    uint32_t link_id;
124
    uint8_t transaction_number;
125
} pbadv_fragment_key;
126
127
static unsigned
128
pbadv_fragment_hash(const void *k)
129
26
{
130
26
    const pbadv_fragment_key* key = (const pbadv_fragment_key*) k;
131
26
    unsigned hash_val;
132
133
26
    hash_val = 0;
134
135
26
    hash_val += key->link_id;
136
26
    hash_val += key->transaction_number;
137
26
    return hash_val;
138
26
}
139
140
static int
141
pbadv_fragment_equal(const void *k1, const void *k2)
142
12
{
143
12
    const pbadv_fragment_key* key1 = (const pbadv_fragment_key*) k1;
144
12
    const pbadv_fragment_key* key2 = (const pbadv_fragment_key*) k2;
145
146
12
    return ((key1->link_id == key2->link_id) && (key1->transaction_number == key2->transaction_number)
147
12
            ? true : false);
148
12
}
149
150
static void *
151
pbadv_fragment_temporary_key(const packet_info *pinfo _U_, const uint32_t id _U_,
152
                              const void *data)
153
20
{
154
20
    pbadv_fragment_key *key = g_slice_new(pbadv_fragment_key);
155
20
    const pbadv_fragment_key *pbadv = (const pbadv_fragment_key *)data;
156
157
20
    key->link_id = pbadv->link_id;
158
20
    key->transaction_number = pbadv->transaction_number;
159
160
20
    return key;
161
20
}
162
163
static void
164
pbadv_fragment_free_temporary_key(void *ptr)
165
20
{
166
20
    pbadv_fragment_key *key = (pbadv_fragment_key *)ptr;
167
168
20
    g_slice_free(pbadv_fragment_key, key);
169
20
}
170
171
static void *
172
pbadv_fragment_persistent_key(const packet_info *pinfo _U_, const uint32_t id _U_,
173
                              const void *data)
174
6
{
175
6
    pbadv_fragment_key *key = g_slice_new(pbadv_fragment_key);
176
6
    const pbadv_fragment_key *pbadv = (const pbadv_fragment_key *)data;
177
178
6
    key->link_id = pbadv->link_id;
179
6
    key->transaction_number = pbadv->transaction_number;
180
181
6
    return key;
182
6
}
183
184
static void
185
pbadv_fragment_free_persistent_key(void *ptr)
186
0
{
187
0
    pbadv_fragment_key *key = (pbadv_fragment_key *)ptr;
188
0
    if (key) {
189
0
        g_slice_free(pbadv_fragment_key, key);
190
0
    }
191
0
}
192
193
static const reassembly_table_functions pbadv_reassembly_table_functions = {
194
    pbadv_fragment_hash,
195
    pbadv_fragment_equal,
196
    pbadv_fragment_temporary_key,
197
    pbadv_fragment_persistent_key,
198
    pbadv_fragment_free_temporary_key,
199
    pbadv_fragment_free_persistent_key
200
};
201
202
static int
203
dissect_btmesh_pbadv_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
204
37
{
205
206
37
    proto_item *item;
207
37
    proto_tree *sub_tree, *sub_tree_generic_provisioning;
208
37
    proto_item *ti;
209
37
    bool defragment = false;
210
37
    unsigned offset = 0;
211
37
    btle_mesh_transport_ctx_t tr_ctx;
212
37
    uint8_t segn, length;
213
37
    uint32_t total_length;
214
37
    uint8_t gpcf_bearer_opcode;
215
216
37
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "BT Mesh PB-ADV");
217
218
37
    item = proto_tree_add_item(tree, proto_btmesh_pbadv, tvb, offset, -1, ENC_NA);
219
37
    sub_tree = proto_item_add_subtree(item, ett_btmesh_pbadv);
220
221
37
    uint32_t pbadv_link_id = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
222
37
    proto_tree_add_item(sub_tree, hf_btmesh_pbadv_linkid, tvb, offset, 4, ENC_BIG_ENDIAN);
223
37
    offset += 4;
224
225
37
    uint8_t pbadv_trnumber = tvb_get_uint8(tvb, offset);
226
37
    proto_tree_add_item(sub_tree, hf_btmesh_pbadv_trnumber, tvb, offset, 1, ENC_NA);
227
37
    offset += 1;
228
229
37
    pbadv_fragment_key frg_key;
230
37
    frg_key.link_id = pbadv_link_id;
231
37
    frg_key.transaction_number = pbadv_trnumber;
232
233
37
    sub_tree_generic_provisioning = proto_tree_add_subtree(sub_tree, tvb, offset, -1, ett_btmesh_generic_provisioning, &ti, "Generic Provisioning PDU");
234
235
37
    proto_tree_add_item(sub_tree_generic_provisioning, hf_btmesh_generic_provisioning_control_format, tvb, offset, 1, ENC_NA);
236
37
    uint8_t gpcf = tvb_get_uint8(tvb, offset) & 0x03;
237
238
37
    col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(gpcf, btmesh_generic_provisioning_control_format, "Unknown PDU"));
239
240
37
    fragment_head *fd_head = NULL;
241
37
    int segment_index = -1;
242
243
37
    switch (gpcf) {
244
        //Transaction Start
245
9
        case TRANSACTION_START:
246
9
            proto_tree_add_item_ret_uint8(sub_tree_generic_provisioning, hf_btmesh_gpcf_segn, tvb, offset, 1, ENC_NA, &segn);
247
9
            offset += 1;
248
9
            proto_tree_add_item_ret_uint(sub_tree_generic_provisioning, hf_btmesh_gpcf_total_length, tvb, offset, 2, ENC_BIG_ENDIAN, &total_length);
249
9
            offset += 2;
250
9
            proto_tree_add_item(sub_tree_generic_provisioning, hf_btmesh_gpcf_fcs, tvb, offset, 1, ENC_NA);
251
9
            offset += 1;
252
9
            segment_index = 0;
253
9
            defragment = true;
254
9
            if (segn == 0) {
255
5
                if (btmesh_provisioning_handle) {
256
5
                    length = tvb_reported_length(tvb);
257
5
                    tr_ctx.transport = E_BTMESH_TR_ADV;
258
5
                    tr_ctx.fragmented = false;
259
5
                    tr_ctx.segment_index = 0;
260
5
                    call_dissector_with_data(btmesh_provisioning_handle, tvb_new_subset_length(tvb, offset, length),
261
5
                        pinfo, proto_tree_get_root(sub_tree_generic_provisioning), &tr_ctx);
262
5
                } else {
263
0
                    proto_tree_add_item(sub_tree_generic_provisioning, hf_btmesh_gpp_payload, tvb, offset, -1, ENC_NA);
264
0
                }
265
5
            } else {
266
                //Segmentation
267
4
                if (!pinfo->fd->visited) {
268
                    //First fragment can be delivered out of order, and can be the last one.
269
4
                    fd_head = fragment_get(&pbadv_reassembly_table, pinfo, BTMESH_PB_ADV_NOT_USED, &frg_key);
270
4
                    if (fd_head) {
271
2
                        fragment_set_tot_len(&pbadv_reassembly_table, pinfo, BTMESH_PB_ADV_NOT_USED, &frg_key, total_length);
272
2
                    }
273
4
                    fd_head = fragment_add(&pbadv_reassembly_table,
274
4
                        tvb, offset, pinfo,
275
4
                        BTMESH_PB_ADV_NOT_USED, &frg_key,
276
4
                        0,
277
4
                        tvb_captured_length_remaining(tvb, offset),
278
4
                        true);
279
4
                    if (!fd_head) {
280
                       //Set the length only when not reassembled
281
2
                       fragment_set_tot_len(&pbadv_reassembly_table, pinfo, BTMESH_PB_ADV_NOT_USED, &frg_key, total_length);
282
2
                    }
283
4
                } else {
284
0
                    proto_tree_add_item(sub_tree_generic_provisioning, hf_btmesh_gpp_payload_fragment, tvb, offset, -1, ENC_NA);
285
0
                }
286
4
            }
287
288
9
        break;
289
        //Transaction Acknowledgment
290
18
        case TRANSACTION_ACKNOWLEDGMENT:
291
18
            proto_tree_add_item(sub_tree_generic_provisioning, hf_btmesh_gpcf_padding, tvb, offset, 1, ENC_NA);
292
293
18
        break;
294
        //Transaction Continuation
295
9
        case TRANSACTION_CONTINUATION:
296
9
            proto_tree_add_item(sub_tree_generic_provisioning, hf_btmesh_gpcf_segment_index, tvb, offset, 1, ENC_NA);
297
9
            segment_index = (tvb_get_uint8(tvb, offset) & 0xFC) >> 2;
298
9
            defragment = true;
299
9
            offset += 1;
300
            //Segmentation
301
9
            if (!pinfo->fd->visited) {
302
9
                fragment_add(&pbadv_reassembly_table,
303
9
                    tvb, offset, pinfo,
304
9
                    BTMESH_PB_ADV_NOT_USED, &frg_key,
305
9
                    20 + (segment_index - 1) * 23,
306
9
                    tvb_captured_length_remaining(tvb, offset),
307
9
                    true);
308
9
            } else {
309
0
                proto_tree_add_item(sub_tree_generic_provisioning, hf_btmesh_gpp_payload_fragment, tvb, offset, -1, ENC_NA);
310
0
            }
311
312
9
        break;
313
        //Provisioning Bearer Control
314
1
        case PROVISIONING_BEARER_CONTROL:
315
1
            proto_tree_add_item_ret_uint8(sub_tree_generic_provisioning, hf_btmesh_gpcf_bearer_opcode, tvb, offset, 1, ENC_NA, &gpcf_bearer_opcode);
316
1
            offset += 1;
317
1
            switch(gpcf_bearer_opcode) {
318
0
                case LINK_OPEN:
319
0
                    proto_tree_add_item(sub_tree_generic_provisioning, hf_btmesh_gpcf_bearer_opcode_device_UUID, tvb, offset, 16, ENC_BIG_ENDIAN);
320
0
                    offset += 16;
321
322
0
                break;
323
0
                case LINK_ACK:
324
                    //No data in this PDU
325
326
0
                break;
327
0
                case LINK_CLOSE:
328
0
                    proto_tree_add_item(sub_tree_generic_provisioning, hf_btmesh_gpcf_bearer_opcode_reason, tvb, offset, 1, ENC_NA);
329
0
                    offset += 1;
330
331
0
                break;
332
1
                default:
333
                    //Unknown data
334
1
                    proto_tree_add_item(sub_tree_generic_provisioning, hf_btmesh_gpcf_bearer_unknown_data, tvb, offset, -1, ENC_NA);
335
1
                    offset += tvb_captured_length_remaining(tvb, offset);
336
1
                    proto_tree_add_expert_remaining(sub_tree, pinfo, &ei_btmesh_gpcf_unknown_opcode, tvb, offset);
337
1
                break;
338
1
            }
339
            //There is still some data but all data should be already disssected
340
1
            if (tvb_captured_length_remaining(tvb, offset) != 0) {
341
0
                proto_tree_add_expert_remaining(sub_tree, pinfo, &ei_btmesh_gpcf_unknown_payload, tvb, offset);
342
0
            }
343
344
1
        break;
345
37
    }
346
    //Second pass
347
35
    if (pinfo->fd->visited && defragment ) {
348
0
        fd_head = fragment_get(&pbadv_reassembly_table, pinfo, BTMESH_PB_ADV_NOT_USED, &frg_key);
349
0
        if (fd_head && (fd_head->flags&FD_DEFRAGMENTED)) {
350
0
            tvbuff_t *next_tvb;
351
0
            next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled Provisioning PDU", fd_head, &btmesh_gpp_frag_items, NULL, sub_tree_generic_provisioning);
352
0
            if (next_tvb) {
353
0
                col_append_str(pinfo->cinfo, COL_INFO, " (Message Reassembled)");
354
0
                if (btmesh_provisioning_handle) {
355
0
                    tr_ctx.transport = E_BTMESH_TR_ADV;
356
0
                    tr_ctx.fragmented = true;
357
0
                    tr_ctx.segment_index = segment_index;
358
0
                    call_dissector_with_data(btmesh_provisioning_handle, next_tvb, pinfo,
359
0
                        proto_tree_get_root(sub_tree_generic_provisioning), &tr_ctx);
360
0
                } else {
361
0
                    proto_tree_add_item(sub_tree_generic_provisioning, hf_btmesh_gpp_payload, next_tvb, 0, -1, ENC_NA);
362
0
                }
363
0
            } else {
364
0
                col_append_fstr(pinfo->cinfo, COL_INFO," (Message fragment %u)", segment_index);
365
0
            }
366
0
        }
367
0
    }
368
369
35
    return tvb_reported_length(tvb);
370
37
}
371
372
void
373
proto_register_btmesh_pbadv(void)
374
14
{
375
14
    static hf_register_info hf[] = {
376
        //PB-ADV
377
14
        { &hf_btmesh_pbadv_linkid,
378
14
            { "Link ID", "pbadv.linkid",
379
14
                FT_UINT32, BASE_DEC, NULL, 0x0,
380
14
                NULL, HFILL }
381
14
        },
382
14
        { &hf_btmesh_pbadv_trnumber,
383
14
            { "Transaction Number", "pbadv.trnumber",
384
14
                FT_UINT8, BASE_DEC, NULL, 0x0,
385
14
                NULL, HFILL }
386
14
        },
387
        //Generic Provisioning Control
388
14
        { &hf_btmesh_generic_provisioning_control_format,
389
14
            { "Generic Provisioning Control Format", "pbadv.gen_prov.gpcf",
390
14
                FT_UINT8, BASE_DEC, VALS(btmesh_generic_provisioning_control_format), 0x03,
391
14
                NULL, HFILL }
392
14
        },
393
14
        { &hf_btmesh_gpcf_segn,
394
14
            { "The last segment number", "pbadv.gen_prov.gpcf.segn",
395
14
                FT_UINT8, BASE_DEC, NULL, 0xFC,
396
14
                NULL, HFILL }
397
14
        },
398
14
        { &hf_btmesh_gpcf_total_length,
399
14
            { "Total Length", "pbadv.gen_prov.gpcf.total_length",
400
14
                FT_UINT16, BASE_DEC, NULL, 0x0,
401
14
                NULL, HFILL }
402
14
        },
403
14
        { &hf_btmesh_gpcf_fcs,
404
14
            { "Frame Check Sequence", "pbadv.gen_prov.gpcf.fcs",
405
14
                FT_UINT8, BASE_HEX, NULL, 0x0,
406
14
                NULL, HFILL }
407
14
        },
408
14
        { &hf_btmesh_gpcf_padding,
409
14
            { "Padding", "pbadv.gen_prov.gpcf.padding",
410
14
                FT_UINT8, BASE_DEC, NULL, 0xFC,
411
14
                NULL, HFILL }
412
14
        },
413
14
        { &hf_btmesh_gpcf_segment_index,
414
14
            { "Segment number of the transaction", "pbadv.gen_prov.gpcf.segment_index",
415
14
                FT_UINT8, BASE_DEC, NULL, 0xFC,
416
14
                NULL, HFILL }
417
14
        },
418
14
        { &hf_btmesh_gpcf_bearer_opcode,
419
14
            { "Bearer Opcode", "pbadv.gen_prov.gpcf.bearer_opcode",
420
14
                FT_UINT8, BASE_DEC, VALS(btmesh_gpcf_bearer_opcode_format), 0xFC,
421
14
                NULL, HFILL }
422
14
        },
423
14
        { &hf_btmesh_gpcf_bearer_opcode_device_UUID,
424
14
            { "Device UUID", "pbadv.gen_prov.gpcf.bearer_opcode.device_uuid",
425
14
                FT_GUID, BASE_NONE, NULL, 0x00,
426
14
                NULL, HFILL }
427
14
        },
428
14
        { &hf_btmesh_gpcf_bearer_opcode_reason,
429
14
            { "Reason", "pbadv.gen_prov.gpcf.bearer_opcode.reason",
430
14
                FT_UINT8, BASE_DEC, VALS(btmesh_gpcf_bearer_opcode_reason_format), 0x00,
431
14
                NULL, HFILL }
432
14
        },
433
14
        { &hf_btmesh_gpcf_bearer_unknown_data,
434
14
            { "Unknown Data", "pbadv.gen_prov.gpcf.unknown_data",
435
14
                FT_BYTES, BASE_NONE, NULL, 0x0,
436
14
                NULL, HFILL }
437
14
        },
438
        //Generic Provisioning Payload
439
14
        { &hf_btmesh_gpp_payload,
440
14
            { "Generic Provisioning Payload", "pbadv.gen_prov.gpp.payload",
441
14
                FT_BYTES, BASE_NONE, NULL, 0x0,
442
14
                NULL, HFILL }
443
14
        },
444
14
        { &hf_btmesh_gpp_payload_fragment,
445
14
            { "Generic Provisioning Payload Fragment", "pbadv.gen_prov.gpp.payload.fragment",
446
14
                FT_BYTES, BASE_NONE, NULL, 0x0,
447
14
                NULL, HFILL }
448
14
        },
449
        //Generic Provisioning Payload Reassembly
450
14
        { &hf_btmesh_gpp_fragments,
451
14
            { "Reassembled Generic Provisioning Payload Fragments", "pbadv.gen_prov.gpp.fragments",
452
14
                FT_NONE, BASE_NONE, NULL, 0x0,
453
14
                NULL, HFILL }
454
14
        },
455
14
        { &hf_btmesh_gpp_fragment,
456
14
            { "Generic Provisioning Payload Fragment", "pbadv.gen_prov.gpp.fragment",
457
14
                FT_FRAMENUM, BASE_NONE, NULL, 0x0,
458
14
                NULL, HFILL }
459
14
        },
460
14
        { &hf_btmesh_gpp_fragment_overlap,
461
14
            { "Fragment overlap", "pbadv.gen_prov.gpp.fragment.overlap",
462
14
                FT_BOOLEAN, BASE_NONE, NULL, 0x0,
463
14
                "Fragment overlaps with other fragments", HFILL }
464
14
        },
465
14
        { &hf_btmesh_gpp_fragment_overlap_conflict,
466
14
            { "Conflicting data in fragment overlap", "pbadv.gen_prov.gpp.fragment.overlap.conflict",
467
14
                FT_BOOLEAN, BASE_NONE, NULL, 0x0,
468
14
                "Overlapping fragments contained conflicting data", HFILL }
469
14
        },
470
14
        { &hf_btmesh_gpp_fragment_multiple_tails,
471
14
            { "Multiple tail fragments found", "pbadv.gen_prov.gpp.fragment.multipletails",
472
14
                FT_BOOLEAN, BASE_NONE, NULL, 0x0,
473
14
                "Several tails were found when defragmenting the packet", HFILL }
474
14
        },
475
14
        { &hf_btmesh_gpp_fragment_too_long_fragment,
476
14
            { "Fragment too long", "pbadv.gen_prov.gpp.fragment.toolongfragment",
477
14
                FT_BOOLEAN, BASE_NONE, NULL, 0x0,
478
14
                "Fragment contained data past end of packet", HFILL }
479
14
        },
480
14
        { &hf_btmesh_gpp_fragment_error,
481
14
            { "Defragmentation error", "pbadv.gen_prov.gpp.fragment.error",
482
14
                FT_FRAMENUM, BASE_NONE, NULL, 0x0,
483
14
                "Defragmentation error due to illegal fragments", HFILL }
484
14
        },
485
14
        { &hf_btmesh_gpp_fragment_count,
486
14
            { "Fragment count", "pbadv.gen_prov.gpp.fragment.count",
487
14
                FT_UINT32, BASE_DEC, NULL, 0x0,
488
14
                NULL, HFILL }
489
14
        },
490
14
        { &hf_btmesh_gpp_reassembled_length,
491
14
            { "Reassembled Generic Provisioning Payload length", "pbadv.gen_prov.gpp.reassembled.length",
492
14
                FT_UINT32, BASE_DEC, NULL, 0x0,
493
14
                "The total length of the reassembled payload", HFILL }
494
14
        },
495
14
    };
496
497
14
    static int *ett[] = {
498
14
        &ett_btmesh_pbadv,
499
14
        &ett_btmesh_generic_provisioning,
500
14
        &ett_btmesh_gpp_fragments,
501
14
        &ett_btmesh_gpp_fragment,
502
14
    };
503
504
14
    static ei_register_info ei[] = {
505
14
        { &ei_btmesh_gpcf_unknown_opcode,{ "pbadv.gpcf.unknown_opcode", PI_PROTOCOL, PI_WARN, "Unknown Opcode", EXPFILL } },
506
14
        { &ei_btmesh_gpcf_unknown_payload,{ "pbadv.gpcf.unknown_payload", PI_PROTOCOL, PI_ERROR, "Unknown Payload", EXPFILL } },
507
14
    };
508
509
14
    expert_module_t* expert_btmesh_pbadv;
510
511
14
    proto_btmesh_pbadv = proto_register_protocol("Bluetooth Mesh PB-ADV", "BT Mesh PB-ADV", "pbadv");
512
513
14
    proto_register_field_array(proto_btmesh_pbadv, hf, array_length(hf));
514
14
    proto_register_subtree_array(ett, array_length(ett));
515
516
14
    expert_btmesh_pbadv = expert_register_protocol(proto_btmesh_pbadv);
517
14
    expert_register_field_array(expert_btmesh_pbadv, ei, array_length(ei));
518
519
14
    prefs_register_protocol_subtree("Bluetooth", proto_btmesh_pbadv, NULL);
520
14
    register_dissector("btmesh.pbadv", dissect_btmesh_pbadv_msg, proto_btmesh_pbadv);
521
522
14
    reassembly_table_register(&pbadv_reassembly_table, &pbadv_reassembly_table_functions);
523
14
}
524
525
void
526
proto_reg_handoff_btmesh_pbadv(void)
527
14
{
528
14
    btmesh_provisioning_handle = find_dissector("btmesh.provisioning");
529
14
}
530
531
/*
532
 * Editor modelines
533
 *
534
 * Local Variables:
535
 * c-basic-offset: 4
536
 * tab-width: 8
537
 * indent-tabs-mode: nil
538
 * End:
539
 *
540
 * ex: set shiftwidth=4 tabstop=8 expandtab:
541
 * :indentSize=4:tabSize=8:noTabs=true:
542
 */