2 * Routines for Matter Bluetooth Transport Protocol (BTP) dissection
3 * Copyright 2024, Arkadiusz Bokowy <a.bokowy@samsung.com>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
13 * The dissector code is based on Matter Specification Version 1.3, section
14 * 4.18. Bluetooth Transport Protocol (BTP).
16 * The specification is available at:
17 * https://csa-iot.org/wp-content/uploads/2024/05/Matter-1.3-Core-Specification.pdf
22 #include <epan/packet.h>
23 #include "packet-btatt.h"
25 void proto_register_btatt_matter(void);
26 void proto_reg_handoff_btatt_matter(void);
28 static int proto_matter_btp
;
29 static dissector_handle_t matter_btp_handle
;
30 static dissector_handle_t matter_tlv_handle
;
32 static int hf_matter_btp_flags
;
33 static int hf_matter_btp_flags_handshake
;
34 static int hf_matter_btp_flags_management
;
35 static int hf_matter_btp_flags_acknowledgment
;
36 static int hf_matter_btp_flags_ending
;
37 static int hf_matter_btp_flags_continuing
;
38 static int hf_matter_btp_flags_beginning
;
39 static int hf_matter_btp_opcode
;
40 static int hf_matter_btp_versions
;
41 static int hf_matter_btp_versions_0
;
42 static int hf_matter_btp_versions_1
;
43 static int hf_matter_btp_versions_2
;
44 static int hf_matter_btp_versions_3
;
45 static int hf_matter_btp_versions_4
;
46 static int hf_matter_btp_versions_5
;
47 static int hf_matter_btp_versions_6
;
48 static int hf_matter_btp_versions_7
;
49 static int hf_matter_btp_version
;
50 static int hf_matter_btp_mtu
;
51 static int hf_matter_btp_window_size
;
52 static int hf_matter_btp_ack
;
53 static int hf_matter_btp_seq
;
54 static int hf_matter_btp_length
;
55 static int hf_matter_btp_payload
;
56 static int hf_matter_btp_ad
;
57 static int hf_matter_btp_ad_tlv_tag
;
59 static int ett_matter_btp
;
60 static int ett_matter_btp_flags
;
61 static int ett_matter_btp_versions
;
62 static int ett_matter_btp_ad
;
65 #define MATTER_BTP_FLAGS_HANDSHAKE 0x40
66 #define MATTER_BTP_FLAGS_MANAGEMENT 0x20
67 #define MATTER_BTP_FLAGS_ACKNOWLEDGMENT 0x08
68 #define MATTER_BTP_FLAGS_ENDING 0x04
69 #define MATTER_BTP_FLAGS_CONTINUING 0x02
70 #define MATTER_BTP_FLAGS_BEGINNING 0x01
73 #define MATTER_BTP_OPCODE_HANDSHAKE 0x6C
76 #define MATTER_BTP_AD_TAG_ROTATING_ID 0x00
79 #define MATTER_GATT_SRV_UUID 0xFFF6
80 // 18EE2EF5-263D-4559-959F-4F9C429F9D11, Client TX Buffer, Write
81 #define MATTER_GATT_CHR_TX_UUID_128 "\x18\xee\x2e\xf5\x26\x3d\x45\x59\x95\x9f\x4f\x9c\x42\x9f\x9d\x11"
82 // 18EE2EF5-263D-4559-959F-4F9C429F9D12, Server RX Buffer, Indication
83 #define MATTER_GATT_CHR_RX_UUID_128 "\x18\xee\x2e\xf5\x26\x3d\x45\x59\x95\x9f\x4f\x9c\x42\x9f\x9d\x12"
84 // 64630238-8772-45F2-B87D-748A83218F04, Additional Data, Read
85 #define MATTER_GATT_CHR_AD_UUID_128 "\x64\x63\x02\x38\x87\x72\x45\xf2\xb8\x7d\x74\x8a\x83\x21\x8f\x04"
87 static const value_string btp_opcode_vals
[] = {
88 { MATTER_BTP_OPCODE_HANDSHAKE
, "Handshake" },
92 static const value_string btp_ad_tag_vals
[] = {
93 { MATTER_BTP_AD_TAG_ROTATING_ID
, "Rotating Device Identifier" },
97 // Dissect the Additional Data characteristic using Matter-defined TLV encoding.
99 dissect_matter_chr_ad_tlv(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int offset
, int length
)
102 col_append_str(pinfo
->cinfo
, COL_INFO
, " Additional Data");
103 proto_item
*item
= proto_tree_add_item(tree
, hf_matter_btp_ad
, tvb
, offset
, length
, ENC_NA
);
104 proto_tree
*subtree
= proto_item_add_subtree(item
, ett_matter_btp_ad
);
106 call_dissector_with_data(matter_tlv_handle
, tvb
, pinfo
, subtree
, &hf_matter_btp_ad_tlv_tag
);
112 dissect_matter_btp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*btatt_tree
, void *data
)
114 btatt_data_t
*att_data
= (btatt_data_t
*) data
;
119 DISSECTOR_ASSERT(att_data
);
120 bluetooth_data_t
*bluetooth_data
= att_data
->bluetooth_data
;
121 const uint8_t att_opcode
= att_data
->opcode
;
122 const uint32_t att_handle
= att_data
->handle
;
124 // We are only interested in read, write and indication packets.
125 if (att_opcode
!= ATT_OPCODE_READ_RESPONSE
&&
126 att_opcode
!= ATT_OPCODE_WRITE_REQUEST
&&
127 att_opcode
!= ATT_OPCODE_HANDLE_VALUE_INDICATION
)
130 /* Get UUID for current ATT handle. */
131 bluetooth_uuid_t uuid
= get_gatt_bluetooth_uuid_from_handle(pinfo
, att_handle
, att_opcode
, bluetooth_data
);
132 /* Verify that the UUID belongs to the Matter GATT service and bail otherwise. */
133 if (uuid
.size
!= 16 || (
134 memcmp(uuid
.data
, MATTER_GATT_CHR_TX_UUID_128
, 16) != 0 &&
135 memcmp(uuid
.data
, MATTER_GATT_CHR_RX_UUID_128
, 16) != 0 &&
136 memcmp(uuid
.data
, MATTER_GATT_CHR_AD_UUID_128
, 16) != 0))
139 /* Check that the packet is long enough to contain BTP flags byte. */
140 if (tvb_reported_length(tvb
) < 1)
143 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "Matter BTP");
145 switch (pinfo
->p2p_dir
) {
147 col_set_str(pinfo
->cinfo
, COL_INFO
, "Sent ");
150 col_set_str(pinfo
->cinfo
, COL_INFO
, "Rcvd ");
153 col_set_str(pinfo
->cinfo
, COL_INFO
, "UnknownDirection ");
157 col_append_str(pinfo
->cinfo
, COL_INFO
, "Matter BTP");
158 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " [Handle: 0x%04x]", att_handle
);
160 /* Add Matter Bluetooth Transport Protocol as a root subtree. */
161 proto_item
*root
= proto_item_get_parent(btatt_tree
);
162 proto_item
*item
= proto_tree_add_item(root
, proto_matter_btp
, tvb
, offset
, -1, ENC_NA
);
163 proto_tree
*tree
= proto_item_add_subtree(item
, ett_matter_btp
);
165 // The payload format of the Additional Data characteristic is different
166 // than the standard BTP packet. It uses Matter-defined TLV encoding.
168 if (memcmp(uuid
.data
, MATTER_GATT_CHR_AD_UUID_128
, 16) == 0)
169 return dissect_matter_chr_ad_tlv(tvb
, pinfo
, tree
, offset
, tvb_reported_length(tvb
));
171 static int * const btp_flags
[] = {
172 &hf_matter_btp_flags_beginning
,
173 &hf_matter_btp_flags_continuing
,
174 &hf_matter_btp_flags_ending
,
175 &hf_matter_btp_flags_acknowledgment
,
176 &hf_matter_btp_flags_management
,
177 &hf_matter_btp_flags_handshake
,
181 static int * const btp_versions
[] = {
182 &hf_matter_btp_versions_0
,
183 &hf_matter_btp_versions_1
,
184 &hf_matter_btp_versions_2
,
185 &hf_matter_btp_versions_3
,
186 &hf_matter_btp_versions_4
,
187 &hf_matter_btp_versions_5
,
188 &hf_matter_btp_versions_6
,
189 &hf_matter_btp_versions_7
,
193 proto_tree_add_bitmask_ret_uint64(tree
, tvb
, offset
, hf_matter_btp_flags
, ett_matter_btp_flags
, btp_flags
, ENC_NA
, &flags
);
196 if (flags
& MATTER_BTP_FLAGS_MANAGEMENT
) {
197 proto_tree_add_item_ret_uint(tree
, hf_matter_btp_opcode
, tvb
, offset
, 1, ENC_NA
, &opcode
);
201 // The handshake packet format is different than standard BTP packets.
203 if (flags
& MATTER_BTP_FLAGS_HANDSHAKE
) {
205 if (opcode
& MATTER_BTP_OPCODE_HANDSHAKE
) {
207 // Section 4.18.3.1. BTP Handshake Request
208 if (memcmp(uuid
.data
, MATTER_GATT_CHR_TX_UUID_128
, 16) == 0) {
210 proto_tree_add_bitmask(tree
, tvb
, offset
, hf_matter_btp_versions
, ett_matter_btp_versions
, btp_versions
, ENC_NA
);
212 proto_tree_add_item(tree
, hf_matter_btp_mtu
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
214 proto_tree_add_item(tree
, hf_matter_btp_window_size
, tvb
, offset
, 1, ENC_NA
);
217 col_append_str(pinfo
->cinfo
, COL_INFO
, " Handshake Request");
220 // Section 4.18.3.2. BTP Handshake Response
221 if (memcmp(uuid
.data
, MATTER_GATT_CHR_RX_UUID_128
, 16) == 0) {
224 proto_tree_add_item_ret_uint(tree
, hf_matter_btp_version
, tvb
, offset
, 1, ENC_NA
, &version
);
228 proto_tree_add_item_ret_uint(tree
, hf_matter_btp_mtu
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
, &mtu
);
231 uint32_t window_size
;
232 proto_tree_add_item_ret_uint(tree
, hf_matter_btp_window_size
, tvb
, offset
, 1, ENC_NA
, &window_size
);
235 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " Handshake Response, Version: %u, MTU: %u, Window Size: %u",
236 version
, mtu
, window_size
);
245 // Mark the packet as a segment of a BTP Service Data Unit.
246 col_append_str(pinfo
->cinfo
, COL_INFO
, " SDU Segment");
248 if (flags
& MATTER_BTP_FLAGS_ACKNOWLEDGMENT
) {
250 proto_tree_add_item_ret_uint(tree
, hf_matter_btp_ack
, tvb
, offset
, 1, ENC_NA
, &ack
);
251 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", Ack: %u", ack
);
255 // All BTP packets SHALL be sent with sequence numbers.
257 if (flags
& (MATTER_BTP_FLAGS_BEGINNING
| MATTER_BTP_FLAGS_CONTINUING
| MATTER_BTP_FLAGS_ENDING
)) {
259 proto_tree_add_item_ret_uint(tree
, hf_matter_btp_seq
, tvb
, offset
, 1, ENC_NA
, &seq
);
260 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", Seq: %u", seq
);
264 // Message length is an optional field present in the Beginning Segment only.
266 if (flags
& MATTER_BTP_FLAGS_BEGINNING
) {
268 proto_tree_add_item_ret_uint(tree
, hf_matter_btp_length
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
, &length
);
269 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", Length: %u", length
);
273 proto_tree_add_item(tree
, hf_matter_btp_payload
, tvb
, offset
, -1, ENC_NA
);
275 return tvb_captured_length(tvb
);
279 proto_register_btatt_matter(void)
281 static hf_register_info hf
[] = {
282 {&hf_matter_btp_flags
,
283 {"Flags", "btp-matter.flags",
284 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
285 "Bluetooth Transport Protocol control flags", HFILL
}
287 {&hf_matter_btp_flags_handshake
,
288 {"Handshake", "btp-matter.flags.handshake",
289 FT_BOOLEAN
, 8, NULL
, MATTER_BTP_FLAGS_HANDSHAKE
,
290 "BTP handshake packet for session establishment", HFILL
}
292 {&hf_matter_btp_flags_management
,
293 {"Management", "btp-matter.flags.management",
294 FT_BOOLEAN
, 8, NULL
, MATTER_BTP_FLAGS_MANAGEMENT
,
295 "Management message with the opcode field", HFILL
}
297 {&hf_matter_btp_flags_acknowledgment
,
298 {"Acknowledgment", "btp-matter.flags.ack",
299 FT_BOOLEAN
, 8, NULL
, MATTER_BTP_FLAGS_ACKNOWLEDGMENT
,
300 "Indicates the presence of the ack number field", HFILL
}
302 {&hf_matter_btp_flags_ending
,
303 {"Ending", "btp-matter.flags.ending",
304 FT_BOOLEAN
, 8, NULL
, MATTER_BTP_FLAGS_ENDING
,
305 "The last segment of a BTP Service Data Unit", HFILL
}
307 {&hf_matter_btp_flags_continuing
,
308 {"Continuing", "btp-matter.flags.continuing",
309 FT_BOOLEAN
, 8, NULL
, MATTER_BTP_FLAGS_CONTINUING
,
310 "The continuation of a BTP Service Data Unit", HFILL
}
312 {&hf_matter_btp_flags_beginning
,
313 {"Beginning", "btp-matter.flags.beginning",
314 FT_BOOLEAN
, 8, NULL
, MATTER_BTP_FLAGS_BEGINNING
,
315 "The first segment of a BTP Service Data Unit", HFILL
}
317 {&hf_matter_btp_opcode
,
318 {"Management Opcode", "btp-matter.opcode",
319 FT_UINT8
, BASE_HEX
, VALS(btp_opcode_vals
), 0x0,
322 {&hf_matter_btp_versions
,
323 {"Supported BTP versions", "btp-matter.versions",
324 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
325 "The list of BTP versions supported by the client", HFILL
}
327 {&hf_matter_btp_versions_0
,
328 {"Version", "btp-matter.versions.0",
329 FT_UINT32
, BASE_DEC
, NULL
, 0x0F000000,
332 {&hf_matter_btp_versions_1
,
333 {"Version", "btp-matter.versions.1",
334 FT_UINT32
, BASE_DEC
, NULL
, 0xF0000000,
337 {&hf_matter_btp_versions_2
,
338 {"Version", "btp-matter.versions.2",
339 FT_UINT32
, BASE_DEC
, NULL
, 0x000F0000,
342 {&hf_matter_btp_versions_3
,
343 {"Version", "btp-matter.versions.3",
344 FT_UINT32
, BASE_DEC
, NULL
, 0x00F00000,
347 {&hf_matter_btp_versions_4
,
348 {"Version", "btp-matter.versions.4",
349 FT_UINT32
, BASE_DEC
, NULL
, 0x00000F00,
352 {&hf_matter_btp_versions_5
,
353 {"Version", "btp-matter.versions.5",
354 FT_UINT32
, BASE_DEC
, NULL
, 0x0000F000,
357 {&hf_matter_btp_versions_6
,
358 {"Version", "btp-matter.versions.6",
359 FT_UINT32
, BASE_DEC
, NULL
, 0x0000000F,
362 {&hf_matter_btp_versions_7
,
363 {"Version", "btp-matter.versions.7",
364 FT_UINT32
, BASE_DEC
, NULL
, 0x000000F0,
367 {&hf_matter_btp_version
,
368 {"Version", "btp-matter.version",
369 FT_UINT8
, BASE_DEC
, NULL
, 0x0F,
370 "The BTP protocol version selected by the server", HFILL
}
373 {"MTU", "btp-matter.mtu",
374 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
375 "Requested or selected MTU for the connection", HFILL
}
377 {&hf_matter_btp_window_size
,
378 {"Window Size", "btp-matter.window",
379 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
380 "Requested or selected maximum receive window size, in units of BTP packets", HFILL
}
383 {"Acknowledgment", "btp-matter.ack",
384 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
385 "The acknowledgement of the previous sequence number", HFILL
}
388 {"Sequence Number", "btp-matter.seq",
389 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
390 "The monotonically increasing sequence number", HFILL
}
392 {&hf_matter_btp_length
,
393 {"Length", "btp-matter.length",
394 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
395 "The payload length, in bytes", HFILL
}
397 {&hf_matter_btp_payload
,
398 {"Payload", "btp-matter.payload",
399 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
400 "The segment of the Service Data Unit message", HFILL
}
403 {"Additional Data", "btp-matter.ad",
404 FT_NONE
, BASE_NONE
, NULL
, 0x0,
405 "Additional commissioning-related data", HFILL
}
407 {&hf_matter_btp_ad_tlv_tag
,
408 {"Tag", "btp-matter.ad.item",
409 FT_UINT8
, BASE_HEX
, VALS(btp_ad_tag_vals
), 0x0,
414 /* Setup protocol subtree array */
415 static int *ett
[] = {
417 &ett_matter_btp_flags
,
418 &ett_matter_btp_versions
,
422 /* Register the protocol name and description */
423 proto_matter_btp
= proto_register_protocol("Matter Bluetooth Transport Protocol", "MatterBTP", "btp-matter");
424 matter_btp_handle
= register_dissector("btp-matter", dissect_matter_btp
, proto_matter_btp
);
426 /* Required function calls to register the header fields and subtrees */
427 proto_register_field_array(proto_matter_btp
, hf
, array_length(hf
));
428 proto_register_subtree_array(ett
, array_length(ett
));
432 proto_reg_handoff_btatt_matter(void)
434 matter_tlv_handle
= find_dissector_add_dependency("matter.tlv", proto_matter_btp
);
435 dissector_add_uint("btatt.service", MATTER_GATT_SRV_UUID
, matter_btp_handle
);