Coverage Report

Created: 2025-08-04 07:15

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