1 /* packet-btmesh-beacon.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
18 #include <epan/packet.h>
19 #include <epan/prefs.h>
20 #include <epan/expert.h>
23 #include "packet-btmesh.h"
25 #define BEACON_UNPROVISION 0x00
26 #define BEACON_SECURE 0x01
28 void proto_register_btmesh_beacon(void);
30 static int proto_btmesh_beacon
;
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
;
59 static int ett_btmesh_beacon
;
60 static int ett_btmesh_beacon_oob
;
61 static int ett_btmesh_beacon_flags
;
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
;
67 static const value_string btmesh_beacon_type
[] = {
68 { 0, "Unprovisioned Device Beacon" },
69 { 1, "Secure Network Beacon" },
73 static const true_false_string flags_key_refresh
= {
74 "Key Refresh in progress",
75 "Key Refresh not in progress"
78 static const true_false_string flags_iv_update
= {
84 dissect_btmesh_beacon_msg(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
87 proto_item
*item
, *oob_item
, *flags_item
;
88 proto_tree
*sub_tree
, *oob_tree
, *flags_tree
;
90 unsigned data_size
= 0;
91 btle_mesh_transport_ctx_t
*tr_ctx
;
92 btle_mesh_transport_ctx_t dummy_ctx
= {E_BTMESH_TR_UNKNOWN
, false, 0};
96 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "BT Mesh Beacon");
101 tr_ctx
= (btle_mesh_transport_ctx_t
*) data
;
104 item
= proto_tree_add_item(tree
, proto_btmesh_beacon
, tvb
, offset
, -1, ENC_NA
);
105 sub_tree
= proto_item_add_subtree(item
, ett_btmesh_beacon
);
107 uint8_t beacon_type
= tvb_get_uint8(tvb
, offset
);
108 proto_tree_add_item(sub_tree
, hf_btmesh_beacon_type
, tvb
, offset
, 1, ENC_NA
);
111 col_set_str(pinfo
->cinfo
, COL_INFO
, val_to_str_const(beacon_type
, btmesh_beacon_type
, "Unknown Beacon Type"));
112 if (tr_ctx
->fragmented
) {
113 switch (tr_ctx
->transport
) {
114 case E_BTMESH_TR_PROXY
:
115 col_append_str(pinfo
->cinfo
, COL_INFO
," (Last Segment)");
119 //No default is needed since this is an additional information only
125 switch(beacon_type
) {
126 case BEACON_UNPROVISION
:
127 proto_tree_add_item(sub_tree
, hf_btmesh_beacon_uuid
, tvb
, offset
, 16, ENC_NA
);
130 oob_item
= proto_tree_add_item(sub_tree
, hf_btmesh_beacon_oob
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
131 oob_tree
= proto_item_add_subtree(oob_item
, ett_btmesh_beacon_oob
);
133 proto_tree_add_item(oob_tree
, hf_btmesh_beacon_oob_other
, tvb
, offset
, 2, ENC_NA
);
134 proto_tree_add_item(oob_tree
, hf_btmesh_beacon_oob_electronic
, tvb
, offset
, 2, ENC_NA
);
135 proto_tree_add_item(oob_tree
, hf_btmesh_beacon_oob_2d_code
, tvb
, offset
, 2, ENC_NA
);
136 proto_tree_add_item(oob_tree
, hf_btmesh_beacon_oob_bar_code
, tvb
, offset
, 2, ENC_NA
);
137 proto_tree_add_item(oob_tree
, hf_btmesh_beacon_oob_nfc
, tvb
, offset
, 2, ENC_NA
);
138 proto_tree_add_item(oob_tree
, hf_btmesh_beacon_oob_number
, tvb
, offset
, 2, ENC_NA
);
139 proto_tree_add_item(oob_tree
, hf_btmesh_beacon_oob_string
, tvb
, offset
, 2, ENC_NA
);
140 proto_tree_add_item(oob_tree
, hf_btmesh_beacon_oob_rfu
, tvb
, offset
, 2, ENC_NA
);
141 proto_tree_add_item(oob_tree
, hf_btmesh_beacon_oob_on_box
, tvb
, offset
, 2, ENC_NA
);
142 proto_tree_add_item(oob_tree
, hf_btmesh_beacon_oob_inside_box
, tvb
, offset
, 2, ENC_NA
);
143 proto_tree_add_item(oob_tree
, hf_btmesh_beacon_oob_on_paper
, tvb
, offset
, 2, ENC_NA
);
144 proto_tree_add_item(oob_tree
, hf_btmesh_beacon_oob_inside_manual
, tvb
, offset
, 2, ENC_NA
);
145 proto_tree_add_item(oob_tree
, hf_btmesh_beacon_oob_on_device
, tvb
, offset
, 2, ENC_NA
);
146 rfu_bits16
= (tvb_get_uint16(tvb
, offset
, ENC_BIG_ENDIAN
) & 0x0780) >> 7;
147 if (rfu_bits16
!= 0) {
148 //RFU bits should be 0
149 proto_tree_add_expert(oob_tree
, pinfo
, &ei_btmesh_beacon_rfu_not_zero
, tvb
, offset
, -1);
153 data_size
= tvb_reported_length(tvb
);
154 if (data_size
== offset
+ 4 ) {
155 proto_tree_add_item(sub_tree
, hf_btmesh_beacon_uri_hash
, tvb
, offset
, 4, ENC_NA
);
158 //Wrong size handled outside switch/case
162 flags_item
= proto_tree_add_item(sub_tree
, hf_btmesh_beacon_flags
, tvb
, offset
, 1, ENC_NA
);
163 flags_tree
= proto_item_add_subtree(flags_item
, ett_btmesh_beacon_flags
);
164 proto_tree_add_item(flags_tree
, hf_btmesh_beacon_flags_key_refresh
, tvb
, offset
, 1, ENC_NA
);
165 proto_tree_add_item(flags_tree
, hf_btmesh_beacon_flags_iv_update
, tvb
, offset
, 1, ENC_NA
);
166 proto_tree_add_item(flags_tree
, hf_btmesh_beacon_flags_rfu
, tvb
, offset
, 1, ENC_NA
);
167 rfu_bits8
= tvb_get_uint8(tvb
, offset
) >> 2;
168 if (rfu_bits8
!= 0) {
169 //RFU bits should be 0
170 proto_tree_add_expert(flags_tree
, pinfo
, &ei_btmesh_beacon_rfu_not_zero
, tvb
, offset
, -1);
173 proto_tree_add_item(sub_tree
, hf_btmesh_beacon_network_id
, tvb
, offset
, 8, ENC_NA
);
175 proto_tree_add_item(sub_tree
, hf_btmesh_beacon_ivindex
, tvb
, offset
, 4, ENC_NA
);
177 proto_tree_add_item(sub_tree
, hf_btmesh_beacon_authentication_value
, tvb
, offset
, 8, ENC_NA
);
181 //Unknown mesh beacon type, display data and flag it
182 proto_tree_add_item(sub_tree
, hf_btmesh_beacon_unknown_data
, tvb
, offset
, -1, ENC_NA
);
183 proto_tree_add_expert(sub_tree
, pinfo
, &ei_btmesh_beacon_unknown_beacon_type
, tvb
, offset
, -1);
184 offset
+= tvb_captured_length_remaining(tvb
, offset
);
187 //There is still some data but all data should be already disssected
188 if (tvb_captured_length_remaining(tvb
, offset
) != 0) {
189 proto_tree_add_expert(sub_tree
, pinfo
, &ei_btmesh_beacon_unknown_payload
, tvb
, offset
, -1);
192 return tvb_reported_length(tvb
);
196 proto_register_btmesh_beacon(void)
198 static hf_register_info hf
[] = {
199 { &hf_btmesh_beacon_type
,
200 { "Type", "beacon.type",
201 FT_UINT8
, BASE_DEC
, VALS(btmesh_beacon_type
), 0x0,
204 { &hf_btmesh_beacon_uuid
,
205 { "Device UUID", "beacon.uuid",
206 FT_GUID
, BASE_NONE
, NULL
, 0x0,
209 { &hf_btmesh_beacon_oob
,
210 { "OOB Information", "beacon.oob",
211 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
214 { &hf_btmesh_beacon_oob_other
,
215 { "Other", "beacon.oob.other",
216 FT_BOOLEAN
, 16, TFS(&tfs_available_not_available
), 0x0001,
219 { &hf_btmesh_beacon_oob_electronic
,
220 { "Electronic / URI", "beacon.oob.electronic",
221 FT_BOOLEAN
, 16, TFS(&tfs_available_not_available
), 0x0002,
224 { &hf_btmesh_beacon_oob_2d_code
,
225 { "2D machine-readable code", "beacon.oob.2d_code",
226 FT_BOOLEAN
, 16, TFS(&tfs_available_not_available
), 0x0004,
229 { &hf_btmesh_beacon_oob_bar_code
,
230 { "Bar code", "beacon.oob.bar_code",
231 FT_BOOLEAN
, 16, TFS(&tfs_available_not_available
), 0x0008,
234 { &hf_btmesh_beacon_oob_nfc
,
235 { "Near Field Communication (NFC)", "beacon.oob.nfc",
236 FT_BOOLEAN
, 16, TFS(&tfs_available_not_available
), 0x0010,
239 { &hf_btmesh_beacon_oob_number
,
240 { "Number", "beacon.oob.number",
241 FT_BOOLEAN
, 16, TFS(&tfs_available_not_available
), 0x0020,
244 { &hf_btmesh_beacon_oob_string
,
245 { "String", "beacon.oob.string",
246 FT_BOOLEAN
, 16, TFS(&tfs_available_not_available
), 0x0040,
249 { &hf_btmesh_beacon_oob_rfu
,
250 { "Reserved for Future Use", "beacon.oob.rfu",
251 FT_UINT16
, BASE_DEC
, NULL
, 0x0780,
254 { &hf_btmesh_beacon_oob_on_box
,
255 { "On box", "beacon.oob.on_box",
256 FT_BOOLEAN
, 16, TFS(&tfs_available_not_available
), 0x0800,
259 { &hf_btmesh_beacon_oob_inside_box
,
260 { "Inside box", "beacon.oob.inside_box",
261 FT_BOOLEAN
, 16, TFS(&tfs_available_not_available
), 0x1000,
264 { &hf_btmesh_beacon_oob_on_paper
,
265 { "On piece of paper", "beacon.oob.on_paper",
266 FT_BOOLEAN
, 16, TFS(&tfs_available_not_available
), 0x2000,
269 { &hf_btmesh_beacon_oob_inside_manual
,
270 { "Inside manual", "beacon.oob.inside_manual",
271 FT_BOOLEAN
, 16, TFS(&tfs_available_not_available
), 0x4000,
274 { &hf_btmesh_beacon_oob_on_device
,
275 { "On device", "beacon.oob.on_device",
276 FT_BOOLEAN
, 16, TFS(&tfs_available_not_available
), 0x8000,
279 { &hf_btmesh_beacon_uri_hash
,
280 { "URI Hash", "beacon.uri_hash",
281 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
284 { &hf_btmesh_beacon_flags
,
285 { "Flags", "beacon.flags",
286 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
289 { &hf_btmesh_beacon_flags_key_refresh
,
290 { "Key Refresh Flag", "beacon.flags.key_refresh",
291 FT_BOOLEAN
, 8, TFS(&flags_key_refresh
), 0x01,
294 { &hf_btmesh_beacon_flags_iv_update
,
295 { "IV Update Flag", "beacon.flags.iv_update",
296 FT_BOOLEAN
, 8, TFS(&flags_iv_update
), 0x02,
299 { &hf_btmesh_beacon_flags_rfu
,
300 { "Reserved for Future Use", "beacon.flags.rfu",
301 FT_UINT8
, BASE_DEC
, NULL
, 0xFC,
304 { &hf_btmesh_beacon_network_id
,
305 { "Network ID", "beacon.network_id",
306 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
309 { &hf_btmesh_beacon_ivindex
,
310 { "IV Index", "beacon.ivindex",
311 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
314 { &hf_btmesh_beacon_authentication_value
,
315 { "Authentication Value", "beacon.authentication_value",
316 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
319 { &hf_btmesh_beacon_unknown_data
,
320 { "Unknown Data", "beacon.unknown_data",
321 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
326 static int *ett
[] = {
328 &ett_btmesh_beacon_oob
,
329 &ett_btmesh_beacon_flags
,
332 static ei_register_info ei
[] = {
333 { &ei_btmesh_beacon_unknown_beacon_type
,{ "beacon.unknown_beacon_type", PI_PROTOCOL
, PI_ERROR
, "Unknown Beacon Type", EXPFILL
} },
334 { &ei_btmesh_beacon_unknown_payload
,{ "beacon.unknown_payload", PI_PROTOCOL
, PI_ERROR
, "Unknown Payload", EXPFILL
} },
335 { &ei_btmesh_beacon_rfu_not_zero
,{ "beacon.rfu_not_zero", PI_PROTOCOL
, PI_WARN
, "Reserved for Future Use value not equal to 0", EXPFILL
} },
338 expert_module_t
* expert_btmesh_beacon
;
340 proto_btmesh_beacon
= proto_register_protocol("Bluetooth Mesh Beacon", "BT Mesh beacon", "beacon");
342 proto_register_field_array(proto_btmesh_beacon
, hf
, array_length(hf
));
343 proto_register_subtree_array(ett
, array_length(ett
));
345 expert_btmesh_beacon
= expert_register_protocol(proto_btmesh_beacon
);
346 expert_register_field_array(expert_btmesh_beacon
, ei
, array_length(ei
));
348 prefs_register_protocol_subtree("Bluetooth", proto_btmesh_beacon
, NULL
);
349 register_dissector("btmesh.beacon", dissect_btmesh_beacon_msg
, proto_btmesh_beacon
);
358 * indent-tabs-mode: nil
361 * ex: set shiftwidth=4 tabstop=8 expandtab:
362 * :indentSize=4:tabSize=8:noTabs=true: