Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-btmesh-pbadv.c
blob39ced414b3dfe9551960079d095d328a70bad6c2
1 /* packet-btmesh-pbadv.c
2 * Routines for Bluetooth mesh PB-ADV dissection
4 * Copyright 2019, Piotr Winiarczyk <wino45@gmail.com>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
12 * Ref: Mesh Profile v1.0
13 * https://www.bluetooth.com/specifications/mesh-specifications
16 #include "config.h"
18 #include <epan/packet.h>
19 #include <epan/prefs.h>
20 #include <epan/reassemble.h>
21 #include <epan/expert.h>
23 #include "packet-btmesh.h"
25 #define BTMESH_PB_ADV_NOT_USED 0
27 #define TRANSACTION_START 0x00
28 #define TRANSACTION_ACKNOWLEDGMENT 0x01
29 #define TRANSACTION_CONTINUATION 0x02
30 #define PROVISIONING_BEARER_CONTROL 0x03
32 #define LINK_OPEN 0x00
33 #define LINK_ACK 0x01
34 #define LINK_CLOSE 0x02
36 void proto_register_btmesh_pbadv(void);
37 void proto_reg_handoff_btmesh_pbadv(void);
39 static int proto_btmesh_pbadv;
41 static dissector_handle_t btmesh_provisioning_handle;
43 static int hf_btmesh_pbadv_linkid;
44 static int hf_btmesh_pbadv_trnumber;
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;
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;
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;
75 static expert_field ei_btmesh_gpcf_unknown_opcode;
76 static expert_field ei_btmesh_gpcf_unknown_payload;
78 static const fragment_items btmesh_gpp_frag_items = {
79 &ett_btmesh_gpp_fragments,
80 &ett_btmesh_gpp_fragment,
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"
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 }
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 }
112 static const value_string btmesh_gpcf_bearer_opcode_reason_format[] = {
113 { 0, "Success" },
114 { 1, "Timeout" },
115 { 2, "Fail" },
116 { 0, NULL }
119 /* needed for packet reassembly */
120 static reassembly_table pbadv_reassembly_table;
122 typedef struct _pbadv_fragment_key {
123 uint32_t link_id;
124 uint8_t transaction_number;
125 } pbadv_fragment_key;
127 static unsigned
128 pbadv_fragment_hash(const void *k)
130 const pbadv_fragment_key* key = (const pbadv_fragment_key*) k;
131 unsigned hash_val;
133 hash_val = 0;
135 hash_val += key->link_id;
136 hash_val += key->transaction_number;
137 return hash_val;
140 static int
141 pbadv_fragment_equal(const void *k1, const void *k2)
143 const pbadv_fragment_key* key1 = (const pbadv_fragment_key*) k1;
144 const pbadv_fragment_key* key2 = (const pbadv_fragment_key*) k2;
146 return ((key1->link_id == key2->link_id) && (key1->transaction_number == key2->transaction_number)
147 ? true : false);
150 static void *
151 pbadv_fragment_temporary_key(const packet_info *pinfo _U_, const uint32_t id _U_,
152 const void *data)
154 pbadv_fragment_key *key = g_slice_new(pbadv_fragment_key);
155 const pbadv_fragment_key *pbadv = (const pbadv_fragment_key *)data;
157 key->link_id = pbadv->link_id;
158 key->transaction_number = pbadv->transaction_number;
160 return key;
163 static void
164 pbadv_fragment_free_temporary_key(void *ptr)
166 pbadv_fragment_key *key = (pbadv_fragment_key *)ptr;
168 g_slice_free(pbadv_fragment_key, key);
171 static void *
172 pbadv_fragment_persistent_key(const packet_info *pinfo _U_, const uint32_t id _U_,
173 const void *data)
175 pbadv_fragment_key *key = g_slice_new(pbadv_fragment_key);
176 const pbadv_fragment_key *pbadv = (const pbadv_fragment_key *)data;
178 key->link_id = pbadv->link_id;
179 key->transaction_number = pbadv->transaction_number;
181 return key;
184 static void
185 pbadv_fragment_free_persistent_key(void *ptr)
187 pbadv_fragment_key *key = (pbadv_fragment_key *)ptr;
188 if (key) {
189 g_slice_free(pbadv_fragment_key, key);
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
202 static int
203 dissect_btmesh_pbadv_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
206 proto_item *item;
207 proto_tree *sub_tree, *sub_tree_generic_provisioning;
208 proto_item *ti;
209 bool defragment = false;
210 int offset = 0;
211 btle_mesh_transport_ctx_t tr_ctx;
212 uint8_t segn, length;
213 uint32_t total_length;
214 uint8_t gpcf_bearer_opcode;
216 col_set_str(pinfo->cinfo, COL_PROTOCOL, "BT Mesh PB-ADV");
218 item = proto_tree_add_item(tree, proto_btmesh_pbadv, tvb, offset, -1, ENC_NA);
219 sub_tree = proto_item_add_subtree(item, ett_btmesh_pbadv);
221 uint32_t pbadv_link_id = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
222 proto_tree_add_item(sub_tree, hf_btmesh_pbadv_linkid, tvb, offset, 4, ENC_NA);
223 offset += 4;
225 uint8_t pbadv_trnumber = tvb_get_uint8(tvb, offset);
226 proto_tree_add_item(sub_tree, hf_btmesh_pbadv_trnumber, tvb, offset, 1, ENC_NA);
227 offset += 1;
229 pbadv_fragment_key frg_key;
230 frg_key.link_id = pbadv_link_id;
231 frg_key.transaction_number = pbadv_trnumber;
233 sub_tree_generic_provisioning = proto_tree_add_subtree(sub_tree, tvb, offset, -1, ett_btmesh_generic_provisioning, &ti, "Generic Provisioning PDU");
235 proto_tree_add_item(sub_tree_generic_provisioning, hf_btmesh_generic_provisioning_control_format, tvb, offset, 1, ENC_NA);
236 uint8_t gpcf = tvb_get_uint8(tvb, offset) & 0x03;
238 col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(gpcf, btmesh_generic_provisioning_control_format, "Unknown PDU"));
240 fragment_head *fd_head = NULL;
241 int segment_index = -1;
243 switch (gpcf) {
244 //Transaction Start
245 case TRANSACTION_START:
246 proto_tree_add_item(sub_tree_generic_provisioning, hf_btmesh_gpcf_segn, tvb, offset, 1, ENC_NA);
247 segn = (tvb_get_uint8(tvb, offset) & 0xFC) >> 2;
248 offset += 1;
249 total_length = (uint32_t)tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
250 proto_tree_add_item(sub_tree_generic_provisioning, hf_btmesh_gpcf_total_length, tvb, offset, 2, ENC_NA);
251 offset += 2;
252 proto_tree_add_item(sub_tree_generic_provisioning, hf_btmesh_gpcf_fcs, tvb, offset, 1, ENC_NA);
253 offset += 1;
254 segment_index = 0;
255 defragment = true;
256 if (segn == 0) {
257 if (btmesh_provisioning_handle) {
258 length = tvb_reported_length(tvb);
259 tr_ctx.transport = E_BTMESH_TR_ADV;
260 tr_ctx.fragmented = false;
261 tr_ctx.segment_index = 0;
262 call_dissector_with_data(btmesh_provisioning_handle, tvb_new_subset_length(tvb, offset, length),
263 pinfo, proto_tree_get_root(sub_tree_generic_provisioning), &tr_ctx);
264 } else {
265 proto_tree_add_item(sub_tree_generic_provisioning, hf_btmesh_gpp_payload, tvb, offset, -1, ENC_NA);
267 } else {
268 //Segmentation
269 if (!pinfo->fd->visited) {
270 //First fragment can be delivered out of order, and can be the last one.
271 fd_head = fragment_get(&pbadv_reassembly_table, pinfo, BTMESH_PB_ADV_NOT_USED, &frg_key);
272 if (fd_head) {
273 fragment_set_tot_len(&pbadv_reassembly_table, pinfo, BTMESH_PB_ADV_NOT_USED, &frg_key, total_length);
275 fd_head = fragment_add(&pbadv_reassembly_table,
276 tvb, offset, pinfo,
277 BTMESH_PB_ADV_NOT_USED, &frg_key,
279 tvb_captured_length_remaining(tvb, offset),
280 true);
281 if (!fd_head) {
282 //Set the length only when not reassembled
283 fragment_set_tot_len(&pbadv_reassembly_table, pinfo, BTMESH_PB_ADV_NOT_USED, &frg_key, total_length);
285 } else {
286 proto_tree_add_item(sub_tree_generic_provisioning, hf_btmesh_gpp_payload_fragment, tvb, offset, -1, ENC_NA);
290 break;
291 //Transaction Acknowledgment
292 case TRANSACTION_ACKNOWLEDGMENT:
293 proto_tree_add_item(sub_tree_generic_provisioning, hf_btmesh_gpcf_padding, tvb, offset, 1, ENC_NA);
295 break;
296 //Transaction Continuation
297 case TRANSACTION_CONTINUATION:
298 proto_tree_add_item(sub_tree_generic_provisioning, hf_btmesh_gpcf_segment_index, tvb, offset, 1, ENC_NA);
299 segment_index = (tvb_get_uint8(tvb, offset) & 0xFC) >> 2;
300 defragment = true;
301 offset += 1;
302 //Segmentation
303 if (!pinfo->fd->visited) {
304 fragment_add(&pbadv_reassembly_table,
305 tvb, offset, pinfo,
306 BTMESH_PB_ADV_NOT_USED, &frg_key,
307 20 + (segment_index - 1) * 23,
308 tvb_captured_length_remaining(tvb, offset),
309 true);
310 } else {
311 proto_tree_add_item(sub_tree_generic_provisioning, hf_btmesh_gpp_payload_fragment, tvb, offset, -1, ENC_NA);
314 break;
315 //Provisioning Bearer Control
316 case PROVISIONING_BEARER_CONTROL:
317 proto_tree_add_item(sub_tree_generic_provisioning, hf_btmesh_gpcf_bearer_opcode, tvb, offset, 1, ENC_NA);
318 gpcf_bearer_opcode = (tvb_get_uint8(tvb, offset) & 0xFC) >> 2;
319 offset += 1;
320 switch(gpcf_bearer_opcode) {
321 case LINK_OPEN:
322 proto_tree_add_item(sub_tree_generic_provisioning, hf_btmesh_gpcf_bearer_opcode_device_UUID, tvb, offset, 16, ENC_NA);
323 offset += 16;
325 break;
326 case LINK_ACK:
327 //No data in this PDU
329 break;
330 case LINK_CLOSE:
331 proto_tree_add_item(sub_tree_generic_provisioning, hf_btmesh_gpcf_bearer_opcode_reason, tvb, offset, 1, ENC_NA);
332 offset += 1;
334 break;
335 default:
336 //Unknown data
337 proto_tree_add_item(sub_tree_generic_provisioning, hf_btmesh_gpcf_bearer_unknown_data, tvb, offset, -1, ENC_NA);
338 offset += tvb_captured_length_remaining(tvb, offset);
339 proto_tree_add_expert(sub_tree, pinfo, &ei_btmesh_gpcf_unknown_opcode, tvb, offset, -1);
340 break;
342 //There is still some data but all data should be already disssected
343 if (tvb_captured_length_remaining(tvb, offset) != 0) {
344 proto_tree_add_expert(sub_tree, pinfo, &ei_btmesh_gpcf_unknown_payload, tvb, offset, -1);
347 break;
349 //Second pass
350 if (pinfo->fd->visited && defragment ) {
351 fd_head = fragment_get(&pbadv_reassembly_table, pinfo, BTMESH_PB_ADV_NOT_USED, &frg_key);
352 if (fd_head && (fd_head->flags&FD_DEFRAGMENTED)) {
353 tvbuff_t *next_tvb;
354 next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled Provisioning PDU", fd_head, &btmesh_gpp_frag_items, NULL, sub_tree_generic_provisioning);
355 if (next_tvb) {
356 col_append_str(pinfo->cinfo, COL_INFO, " (Message Reassembled)");
357 if (btmesh_provisioning_handle) {
358 tr_ctx.transport = E_BTMESH_TR_ADV;
359 tr_ctx.fragmented = true;
360 tr_ctx.segment_index = segment_index;
361 call_dissector_with_data(btmesh_provisioning_handle, next_tvb, pinfo,
362 proto_tree_get_root(sub_tree_generic_provisioning), &tr_ctx);
363 } else {
364 proto_tree_add_item(sub_tree_generic_provisioning, hf_btmesh_gpp_payload, next_tvb, 0, -1, ENC_NA);
366 } else {
367 col_append_fstr(pinfo->cinfo, COL_INFO," (Message fragment %u)", segment_index);
372 return tvb_reported_length(tvb);
375 void
376 proto_register_btmesh_pbadv(void)
378 static hf_register_info hf[] = {
379 //PB-ADV
380 { &hf_btmesh_pbadv_linkid,
381 { "Link ID", "pbadv.linkid",
382 FT_UINT32, BASE_DEC, NULL, 0x0,
383 NULL, HFILL }
385 { &hf_btmesh_pbadv_trnumber,
386 { "Transaction Number", "pbadv.trnumber",
387 FT_UINT8, BASE_DEC, NULL, 0x0,
388 NULL, HFILL }
390 //Generic Provisioning Control
391 { &hf_btmesh_generic_provisioning_control_format,
392 { "Generic Provisioning Control Format", "pbadv.gen_prov.gpcf",
393 FT_UINT8, BASE_DEC, VALS(btmesh_generic_provisioning_control_format), 0x03,
394 NULL, HFILL }
396 { &hf_btmesh_gpcf_segn,
397 { "The last segment number", "pbadv.gen_prov.gpcf.segn",
398 FT_UINT8, BASE_DEC, NULL, 0xFC,
399 NULL, HFILL }
401 { &hf_btmesh_gpcf_total_length,
402 { "Total Length", "pbadv.gen_prov.gpcf.total_length",
403 FT_UINT16, BASE_DEC, NULL, 0x0,
404 NULL, HFILL }
406 { &hf_btmesh_gpcf_fcs,
407 { "Frame Check Sequence", "pbadv.gen_prov.gpcf.fcs",
408 FT_UINT8, BASE_HEX, NULL, 0x0,
409 NULL, HFILL }
411 { &hf_btmesh_gpcf_padding,
412 { "Padding", "pbadv.gen_prov.gpcf.padding",
413 FT_UINT8, BASE_DEC, NULL, 0xFC,
414 NULL, HFILL }
416 { &hf_btmesh_gpcf_segment_index,
417 { "Segment number of the transaction", "pbadv.gen_prov.gpcf.segment_index",
418 FT_UINT8, BASE_DEC, NULL, 0xFC,
419 NULL, HFILL }
421 { &hf_btmesh_gpcf_bearer_opcode,
422 { "Bearer Opcode", "pbadv.gen_prov.gpcf.bearer_opcode",
423 FT_UINT8, BASE_DEC, VALS(btmesh_gpcf_bearer_opcode_format), 0xFC,
424 NULL, HFILL }
426 { &hf_btmesh_gpcf_bearer_opcode_device_UUID,
427 { "Device UUID", "pbadv.gen_prov.gpcf.bearer_opcode.device_uuid",
428 FT_GUID, BASE_NONE, NULL, 0x00,
429 NULL, HFILL }
431 { &hf_btmesh_gpcf_bearer_opcode_reason,
432 { "Reason", "pbadv.gen_prov.gpcf.bearer_opcode.reason",
433 FT_UINT8, BASE_DEC, VALS(btmesh_gpcf_bearer_opcode_reason_format), 0x00,
434 NULL, HFILL }
436 { &hf_btmesh_gpcf_bearer_unknown_data,
437 { "Unknown Data", "pbadv.gen_prov.gpcf.unknown_data",
438 FT_BYTES, BASE_NONE, NULL, 0x0,
439 NULL, HFILL }
441 //Generic Provisioning Payload
442 { &hf_btmesh_gpp_payload,
443 { "Generic Provisioning Payload", "pbadv.gen_prov.gpp.payload",
444 FT_BYTES, BASE_NONE, NULL, 0x0,
445 NULL, HFILL }
447 { &hf_btmesh_gpp_payload_fragment,
448 { "Generic Provisioning Payload Fragment", "pbadv.gen_prov.gpp.payload.fragment",
449 FT_BYTES, BASE_NONE, NULL, 0x0,
450 NULL, HFILL }
452 //Generic Provisioning Payload Reassembly
453 { &hf_btmesh_gpp_fragments,
454 { "Reassembled Generic Provisioning Payload Fragments", "pbadv.gen_prov.gpp.fragments",
455 FT_NONE, BASE_NONE, NULL, 0x0,
456 NULL, HFILL }
458 { &hf_btmesh_gpp_fragment,
459 { "Generic Provisioning Payload Fragment", "pbadv.gen_prov.gpp.fragment",
460 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
461 NULL, HFILL }
463 { &hf_btmesh_gpp_fragment_overlap,
464 { "Fragment overlap", "pbadv.gen_prov.gpp.fragment.overlap",
465 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
466 "Fragment overlaps with other fragments", HFILL }
468 { &hf_btmesh_gpp_fragment_overlap_conflict,
469 { "Conflicting data in fragment overlap", "pbadv.gen_prov.gpp.fragment.overlap.conflict",
470 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
471 "Overlapping fragments contained conflicting data", HFILL }
473 { &hf_btmesh_gpp_fragment_multiple_tails,
474 { "Multiple tail fragments found", "pbadv.gen_prov.gpp.fragment.multipletails",
475 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
476 "Several tails were found when defragmenting the packet", HFILL }
478 { &hf_btmesh_gpp_fragment_too_long_fragment,
479 { "Fragment too long", "pbadv.gen_prov.gpp.fragment.toolongfragment",
480 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
481 "Fragment contained data past end of packet", HFILL }
483 { &hf_btmesh_gpp_fragment_error,
484 { "Defragmentation error", "pbadv.gen_prov.gpp.fragment.error",
485 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
486 "Defragmentation error due to illegal fragments", HFILL }
488 { &hf_btmesh_gpp_fragment_count,
489 { "Fragment count", "pbadv.gen_prov.gpp.fragment.count",
490 FT_UINT32, BASE_DEC, NULL, 0x0,
491 NULL, HFILL }
493 { &hf_btmesh_gpp_reassembled_length,
494 { "Reassembled Generic Provisioning Payload length", "pbadv.gen_prov.gpp.reassembled.length",
495 FT_UINT32, BASE_DEC, NULL, 0x0,
496 "The total length of the reassembled payload", HFILL }
500 static int *ett[] = {
501 &ett_btmesh_pbadv,
502 &ett_btmesh_generic_provisioning,
503 &ett_btmesh_gpp_fragments,
504 &ett_btmesh_gpp_fragment,
507 static ei_register_info ei[] = {
508 { &ei_btmesh_gpcf_unknown_opcode,{ "pbadv.gpcf.unknown_opcode", PI_PROTOCOL, PI_WARN, "Unknown Opcode", EXPFILL } },
509 { &ei_btmesh_gpcf_unknown_payload,{ "pbadv.gpcf.unknown_payload", PI_PROTOCOL, PI_ERROR, "Unknown Payload", EXPFILL } },
512 expert_module_t* expert_btmesh_pbadv;
514 proto_btmesh_pbadv = proto_register_protocol("Bluetooth Mesh PB-ADV", "BT Mesh PB-ADV", "pbadv");
516 proto_register_field_array(proto_btmesh_pbadv, hf, array_length(hf));
517 proto_register_subtree_array(ett, array_length(ett));
519 expert_btmesh_pbadv = expert_register_protocol(proto_btmesh_pbadv);
520 expert_register_field_array(expert_btmesh_pbadv, ei, array_length(ei));
522 prefs_register_protocol_subtree("Bluetooth", proto_btmesh_pbadv, NULL);
523 register_dissector("btmesh.pbadv", dissect_btmesh_pbadv_msg, proto_btmesh_pbadv);
525 reassembly_table_register(&pbadv_reassembly_table, &pbadv_reassembly_table_functions);
528 void
529 proto_reg_handoff_btmesh_pbadv(void)
531 btmesh_provisioning_handle = find_dissector("btmesh.provisioning");
535 * Editor modelines
537 * Local Variables:
538 * c-basic-offset: 4
539 * tab-width: 8
540 * indent-tabs-mode: nil
541 * End:
543 * ex: set shiftwidth=4 tabstop=8 expandtab:
544 * :indentSize=4:tabSize=8:noTabs=true: