2 * Routines for Matter IoT protocol dissection
3 * Copyright 2023, Nicolás Alvarez <nicolas.alvarez@gmail.com>
4 * Copyright 2024, Arkadiusz Bokowy <a.bokowy@samsung.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
14 * The Matter protocol provides an interoperable application
15 * layer solution for smart home devices over IPv6.
17 * The specification can be freely requested at:
18 * https://csa-iot.org/developer-resource/specifications-download-request/
20 * Comments below reference section numbers of the Matter Core Specification R1.0 (22-27349-001).
22 * Matter-TLV dissector is based on Matter Specification Version 1.3.
27 #include <epan/expert.h>
28 #include <epan/packet.h>
29 #include <wsutil/array.h>
32 /* (Required to prevent [-Wmissing-prototypes] warnings */
33 void proto_reg_handoff_matter(void);
34 void proto_register_matter(void);
36 /* Initialize the protocol and registered fields */
37 static dissector_handle_t matter_handle
;
39 static int proto_matter
;
40 static int hf_message_flags
;
41 static int hf_message_version
;
42 static int hf_message_has_source
;
43 static int hf_message_dsiz
;
44 static int hf_message_session_id
;
45 static int hf_message_security_flags
;
46 static int hf_message_flag_privacy
;
47 static int hf_message_flag_control
;
48 static int hf_message_flag_extensions
;
49 static int hf_message_session_type
;
50 static int hf_message_counter
;
51 static int hf_message_src_id
;
52 static int hf_message_dest_id
;
53 static int hf_message_privacy_header
;
55 static int hf_payload
;
56 static int hf_payload_exchange_flags
;
57 static int hf_payload_flag_initiator
;
58 static int hf_payload_flag_ack
;
59 static int hf_payload_flag_reliability
;
60 static int hf_payload_flag_secured_extensions
;
61 static int hf_payload_flag_vendor
;
62 static int hf_payload_protocol_opcode
;
63 static int hf_payload_exchange_id
;
64 static int hf_payload_protocol_vendor_id
;
65 static int hf_payload_protocol_id
;
66 static int hf_payload_ack_counter
;
67 static int hf_payload_secured_ext_length
;
68 static int hf_payload_secured_ext
;
69 static int hf_payload_application
;
71 static int hf_matter_tlv_elem
;
72 static int hf_matter_tlv_elem_control
;
73 static int hf_matter_tlv_elem_control_tag_format
;
74 static int hf_matter_tlv_elem_control_element_type
;
75 static int hf_matter_tlv_elem_tag
;
76 static int hf_matter_tlv_elem_length
;
77 static int hf_matter_tlv_elem_value_int
;
78 static int hf_matter_tlv_elem_value_uint
;
79 static int hf_matter_tlv_elem_value_bytes
;
81 static int ett_matter
;
82 static int ett_message_flags
;
83 static int ett_security_flags
;
84 static int ett_payload
;
85 static int ett_exchange_flags
;
87 static int ett_matter_tlv
;
88 static int ett_matter_tlv_control
;
90 static expert_field ei_matter_tlv_unsupported_control
;
92 /* message flags + session ID + security flags + counter */
93 #define MATTER_MIN_LENGTH 8
96 #define MESSAGE_FLAG_VERSION_MASK 0xF0
97 #define MESSAGE_FLAG_HAS_SOURCE 0x04
98 #define MESSAGE_FLAG_HAS_DEST_NODE 0x01
99 #define MESSAGE_FLAG_HAS_DEST_GROUP 0x02
100 #define MESSAGE_FLAG_DSIZ_MASK 0x03
103 #define SECURITY_FLAG_HAS_PRIVACY 0x80
104 #define SECURITY_FLAG_IS_CONTROL 0x40
105 #define SECURITY_FLAG_HAS_EXTENSIONS 0x20
106 #define SECURITY_FLAG_SESSION_TYPE_MASK 0x03
109 #define EXCHANGE_FLAG_IS_INITIATOR 0x01
110 #define EXCHANGE_FLAG_ACK_MSG 0x02
111 #define EXCHANGE_FLAG_RELIABILITY 0x04
112 #define EXCHANGE_FLAG_HAS_SECURED_EXT 0x08
113 #define EXCHANGE_FLAG_HAS_VENDOR_PROTO 0x10
115 static const value_string dsiz_vals
[] = {
116 { 0, "Not present" },
117 { MESSAGE_FLAG_HAS_DEST_NODE
, "64-bit Node ID" },
118 { MESSAGE_FLAG_HAS_DEST_GROUP
, "16-bit Group ID" },
122 static const value_string session_type_vals
[] = {
123 { 0, "Unicast Session" },
124 { 1, "Group Session" },
128 // Appendix 7.2. Tag Control Field
129 static const value_string matter_tlv_tag_format_vals
[] = {
130 { 0, "Anonymous Tag Form, 0 octets" },
131 { 1, "Context-specific Tag Form, 1 octet" },
132 { 2, "Common Profile Tag Form, 2 octets" },
133 { 3, "Common Profile Tag Form, 4 octets" },
134 { 4, "Implicit Profile Tag Form, 2 octets" },
135 { 5, "Implicit Profile Tag Form, 4 octets" },
136 { 6, "Fully-qualified Tag Form, 6 octets" },
137 { 7, "Fully-qualified Tag Form, 8 octets" },
141 // Appendix 7.1. Element Type Field
142 static const value_string matter_tlv_elem_type_vals
[] = {
143 { 0x00, "Signed Integer, 1-octet value" },
144 { 0x01, "Signed Integer, 2-octet value" },
145 { 0x02, "Signed Integer, 4-octet value" },
146 { 0x03, "Signed Integer, 8-octet value" },
147 { 0x04, "Unsigned Integer, 1-octet value" },
148 { 0x05, "Unsigned Integer, 2-octet value" },
149 { 0x06, "Unsigned Integer, 4-octet value" },
150 { 0x07, "Unsigned Integer, 8-octet value" },
151 { 0x08, "Boolean False" },
152 { 0x09, "Boolean True" },
153 { 0x0A, "Floating Point Number, 4-octet value" },
154 { 0x0B, "Floating Point Number, 8-octet value" },
155 { 0x0C, "UTF-8 String, 1-octet length" },
156 { 0x0D, "UTF-8 String, 2-octet length" },
157 { 0x0E, "UTF-8 String, 4-octet length" },
158 { 0x0F, "UTF-8 String, 8-octet length" },
159 { 0x10, "Octet String, 1-octet length" },
160 { 0x11, "Octet String, 2-octet length" },
161 { 0x12, "Octet String, 4-octet length" },
162 { 0x13, "Octet String, 8-octet length" },
164 { 0x15, "Structure" },
167 // XXX: If the Tag Control Field is set to 0x00 (Anonymous Tag), the
168 // value of 0x18 means "End of Container". For other Tag Control
169 // Field values, the value of 0x18 is reserved.
170 // TODO: This should be handled in the dissector.
171 { 0x18, "End of Container" },
172 { 0x19, "Reserved" },
173 { 0x1A, "Reserved" },
174 { 0x1B, "Reserved" },
175 { 0x1C, "Reserved" },
176 { 0x1D, "Reserved" },
177 { 0x1E, "Reserved" },
178 { 0x1F, "Reserved" },
183 dissect_matter_payload(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*pl_tree
);
186 dissect_matter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
189 proto_tree
*matter_tree
;
192 /* info extracted from the packet */
193 uint8_t message_flags
= 0;
194 uint8_t security_flags
= 0;
195 uint8_t message_dsiz
= 0;
196 uint8_t message_session_type
= 0;
197 uint32_t session_id
= 0;
199 /* Check that the packet is long enough for it to belong to us. */
200 if (tvb_reported_length(tvb
) < MATTER_MIN_LENGTH
)
203 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "Matter");
205 /* create display subtree for the protocol */
206 ti
= proto_tree_add_item(tree
, proto_matter
, tvb
, 0, -1, ENC_NA
);
208 matter_tree
= proto_item_add_subtree(ti
, ett_matter
);
210 static int* const message_flag_fields
[] = {
212 &hf_message_has_source
,
216 static int* const message_secflag_fields
[] = {
217 &hf_message_flag_privacy
,
218 &hf_message_flag_control
,
219 &hf_message_flag_extensions
,
220 &hf_message_session_type
,
225 proto_tree_add_bitmask(matter_tree
, tvb
, offset
, hf_message_flags
, ett_message_flags
, message_flag_fields
, ENC_LITTLE_ENDIAN
);
226 message_flags
= tvb_get_uint8(tvb
, offset
);
227 message_dsiz
= (message_flags
& MESSAGE_FLAG_DSIZ_MASK
);
231 proto_tree_add_item_ret_uint(matter_tree
, hf_message_session_id
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
, &session_id
);
235 proto_tree_add_bitmask(matter_tree
, tvb
, offset
, hf_message_security_flags
, ett_security_flags
, message_secflag_fields
, ENC_LITTLE_ENDIAN
);
236 security_flags
= tvb_get_uint8(tvb
, offset
);
237 message_session_type
= (security_flags
& SECURITY_FLAG_SESSION_TYPE_MASK
);
240 // decryption of message privacy is not yet supported,
241 // but add an opaque field with the encrypted blob
243 if (security_flags
& SECURITY_FLAG_HAS_PRIVACY
) {
245 uint32_t privacy_header_length
= 4;
246 if (message_flags
& MESSAGE_FLAG_HAS_SOURCE
) {
247 privacy_header_length
+= 8;
249 if (message_dsiz
== MESSAGE_FLAG_HAS_DEST_NODE
) {
250 privacy_header_length
+= 8;
251 } else if (message_dsiz
== MESSAGE_FLAG_HAS_DEST_GROUP
) {
252 privacy_header_length
+= 2;
254 proto_tree_add_bytes_format(matter_tree
, hf_message_privacy_header
, tvb
, offset
, privacy_header_length
, NULL
, "Encrypted Headers");
255 offset
+= privacy_header_length
;
260 proto_tree_add_item(matter_tree
, hf_message_counter
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
264 if (message_flags
& MESSAGE_FLAG_HAS_SOURCE
) {
265 proto_tree_add_item(matter_tree
, hf_message_src_id
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
269 if (message_dsiz
== MESSAGE_FLAG_HAS_DEST_NODE
) {
270 proto_tree_add_item(matter_tree
, hf_message_dest_id
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
272 } else if (message_dsiz
== MESSAGE_FLAG_HAS_DEST_GROUP
) {
273 proto_tree_add_item(matter_tree
, hf_message_dest_id
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
279 // Section 4.4.1.4: "The Unsecured Session SHALL be indicated
280 // when both Session Type and Session ID are set to 0."
281 // Secured sessions not yet supported in the dissector.
282 if (message_session_type
== 0 && session_id
== 0) {
283 proto_item
*payload_item
= proto_tree_add_none_format(matter_tree
, hf_payload
, tvb
, offset
, -1, "Protocol Payload");
284 proto_tree
*payload_tree
= proto_item_add_subtree(payload_item
, ett_payload
);
285 tvbuff_t
*next_tvb
= tvb_new_subset_remaining(tvb
, offset
);
287 offset
+= dissect_matter_payload(next_tvb
, pinfo
, payload_tree
);
289 uint32_t payload_length
= tvb_reported_length_remaining(tvb
, offset
);
290 proto_tree_add_none_format(matter_tree
, hf_payload
, tvb
, offset
, payload_length
, "Encrypted Payload (%u bytes)", payload_length
);
297 dissect_matter_payload(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*pl_tree
)
301 uint8_t exchange_flags
= 0;
303 static int* const exchange_flag_fields
[] = {
304 &hf_payload_flag_initiator
,
305 &hf_payload_flag_ack
,
306 &hf_payload_flag_reliability
,
307 &hf_payload_flag_secured_extensions
,
308 &hf_payload_flag_vendor
,
312 proto_tree_add_bitmask(pl_tree
, tvb
, offset
, hf_payload_exchange_flags
, ett_exchange_flags
, exchange_flag_fields
, ENC_LITTLE_ENDIAN
);
313 exchange_flags
= tvb_get_uint8(tvb
, offset
);
317 proto_tree_add_item(pl_tree
, hf_payload_protocol_opcode
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
321 proto_tree_add_item(pl_tree
, hf_payload_exchange_id
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
324 if (exchange_flags
& EXCHANGE_FLAG_HAS_VENDOR_PROTO
) {
325 // NOTE: The Matter specification R1.0 (22-27349) section 4.4 says
326 // the Vendor ID comes after the Protocol ID. However, the SDK
327 // implementation expects and produces the vendor ID first and the
328 // protocol ID afterwards. This was reported, and the maintainers
329 // declared it a bug in the *specification*, which will be resolved
330 // in a future version:
331 // https://github.com/project-chip/connectedhomeip/issues/25003
332 // So we parse Vendor ID first, contrary to the current spec.
333 proto_tree_add_item(pl_tree
, hf_payload_protocol_vendor_id
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
338 proto_tree_add_item(pl_tree
, hf_payload_protocol_id
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
342 if (exchange_flags
& EXCHANGE_FLAG_ACK_MSG
) {
343 proto_tree_add_item(pl_tree
, hf_payload_ack_counter
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
348 if (exchange_flags
& EXCHANGE_FLAG_HAS_SECURED_EXT
) {
349 uint32_t secured_ext_len
= 0;
350 proto_tree_add_item_ret_uint(pl_tree
, hf_payload_secured_ext_length
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
, &secured_ext_len
);
352 proto_tree_add_item(pl_tree
, hf_payload_secured_ext
, tvb
, offset
, secured_ext_len
, ENC_NA
);
353 offset
+= secured_ext_len
;
355 uint32_t application_length
= tvb_reported_length_remaining(tvb
, offset
);
356 proto_tree_add_bytes_format(pl_tree
, hf_payload_application
, tvb
, offset
, application_length
, NULL
, "Application payload (%u bytes)", application_length
);
357 offset
+= application_length
;
361 // Dissect the Matter-defined TLV encoding.
362 // Appendix A: Tag-length-value (TLV) Encoding Format
364 // NOLINTNEXTLINE(misc-no-recursion)
365 dissect_matter_tlv(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
367 // For signed and unsigned integer types and for UTF-8 and octet strings,
368 // the length is encoded in the lowest 2 bits of the control byte.
369 static const int elem_sizes
[] = { 1, 2, 4, 8 };
371 int matter_tlv_elem_tag
= hf_matter_tlv_elem_tag
;
372 int length
= tvb_reported_length_remaining(tvb
, 0);
376 // Use caller-provided tag field.
377 matter_tlv_elem_tag
= *((int *)data
);
379 while (offset
< length
) {
381 // The new element is created with initial length set to 1 which accounts
382 // for the control byte (tag format and element type). The length will be
383 // updated once the element is fully dissected.
384 proto_item
*ti_element
= proto_tree_add_item(tree
, hf_matter_tlv_elem
, tvb
, offset
, 1, ENC_NA
);
385 proto_tree
*tree_element
= proto_item_add_subtree(ti_element
, ett_matter_tlv
);
386 int base_offset
= offset
;
388 uint32_t control_tag_format
= 0;
389 uint32_t control_element
= 0;
391 proto_item
*ti_control
= proto_tree_add_item(tree_element
, hf_matter_tlv_elem_control
, tvb
, offset
, 1, ENC_NA
);
392 proto_tree
*tree_control
= proto_item_add_subtree(ti_control
, ett_matter_tlv_control
);
393 // The tag format is determined by the upper 3 bits of the control byte.
394 proto_tree_add_item_ret_uint(tree_control
, hf_matter_tlv_elem_control_tag_format
, tvb
, offset
, 1, ENC_NA
, &control_tag_format
);
395 // The element type is determined by the lower 5 bits of the control byte.
396 proto_tree_add_item_ret_uint(tree_control
, hf_matter_tlv_elem_control_element_type
, tvb
, offset
, 1, ENC_NA
, &control_element
);
400 proto_item_append_text(ti_element
, ": %s", val_to_str_const(control_element
, matter_tlv_elem_type_vals
, "Unknown"));
402 // The control byte 0x18 means "End of Container".
403 if (control_tag_format
== 0 && control_element
== 0x18)
406 switch (control_tag_format
)
408 case 0: // Anonymous Tag Form (0 octets)
410 case 1: // Context-specific Tag Form (1 octet)
411 proto_tree_add_item(tree_element
, matter_tlv_elem_tag
, tvb
, offset
, 1, ENC_NA
);
415 goto unsupported_control
;
418 // The string length might be encoded on 1, 2, 4 or 8 octets. In theory,
419 // the length can be up to 2^64 - 1 bytes, but in practice, it should be
420 // limited to a reasonable value (it should be safe to assume that the
421 // length will not exceed 2^16 - 1 bytes).
424 switch (control_element
)
426 case 0x00: // Signed Integer, 1-octet value
427 case 0x01: // Signed Integer, 2-octet value
428 case 0x02: // Signed Integer, 4-octet value
429 case 0x03: // Signed Integer, 8-octet value
430 case 0x04: // Unsigned Integer, 1-octet value
431 case 0x05: // Unsigned Integer, 2-octet value
432 case 0x06: // Unsigned Integer, 4-octet value
433 case 0x07: // Unsigned Integer, 8-octet value
435 // Integer type (signed or unsigned) is encoded in the 3rd bit of the control element.
436 int hf
= (control_element
& 0x04) ? hf_matter_tlv_elem_value_uint
: hf_matter_tlv_elem_value_int
;
437 int size
= elem_sizes
[control_element
& 0x03];
438 proto_tree_add_item(tree_element
, hf
, tvb
, offset
, size
, ENC_LITTLE_ENDIAN
);
442 case 0x08: // Boolean False
443 case 0x09: // Boolean True
445 case 0x10: // Octet String (1-octet length)
446 case 0x11: // Octet String (2-octet length)
447 case 0x12: // Octet String (4-octet length)
448 case 0x13: // Octet String (8-octet length)
450 int size
= elem_sizes
[control_element
& 0x03];
451 proto_tree_add_item_ret_uint64(tree_element
, hf_matter_tlv_elem_length
, tvb
, offset
, size
, ENC_LITTLE_ENDIAN
, &str_length
);
453 proto_tree_add_item(tree_element
, hf_matter_tlv_elem_value_bytes
, tvb
, offset
, (int)str_length
, ENC_NA
);
454 offset
+= (int)str_length
;
459 case 0x15: // Structure
462 offset
+= dissect_matter_tlv(tvb_new_subset_remaining(tvb
, offset
), pinfo
, tree_element
, data
);
465 goto unsupported_control
;
468 proto_item_set_len(ti_element
, offset
- base_offset
);
472 expert_add_info(pinfo
, tree_control
, &ei_matter_tlv_unsupported_control
);
473 proto_item_set_len(ti_element
, offset
- base_offset
);
481 proto_register_matter(void)
483 static hf_register_info hf
[] = {
485 { "Message Flags", "matter.message.flags",
486 FT_UINT8
, BASE_HEX
, NULL
, 0,
489 { &hf_message_version
,
490 { "Version", "matter.message.version",
491 FT_UINT8
, BASE_DEC
, NULL
, MESSAGE_FLAG_VERSION_MASK
,
492 "Message format version", HFILL
}
494 { &hf_message_has_source
,
495 { "Has Source ID", "matter.message.has_source_id",
496 FT_BOOLEAN
, 8, NULL
, MESSAGE_FLAG_HAS_SOURCE
,
497 "Source ID field is present", HFILL
}
500 { "Destination ID Type", "matter.message.dsiz",
501 FT_UINT8
, BASE_DEC
, VALS(dsiz_vals
), MESSAGE_FLAG_DSIZ_MASK
,
502 "Size and meaning of the Destination Node ID field", HFILL
}
504 { &hf_message_session_id
,
505 { "Session ID", "matter.message.session_id",
506 FT_UINT16
, BASE_HEX
, NULL
, 0,
507 "The session associated with this message", HFILL
}
509 { &hf_message_security_flags
,
510 { "Security Flags", "matter.message.security_flags",
511 FT_UINT8
, BASE_HEX
, NULL
, 0,
512 "Message security flags", HFILL
}
514 { &hf_message_flag_privacy
,
515 { "Privacy", "matter.message.has_privacy",
516 FT_BOOLEAN
, 8, NULL
, SECURITY_FLAG_HAS_PRIVACY
,
517 "Whether the message is encoded with privacy enhancements", HFILL
}
519 { &hf_message_flag_control
,
520 { "Control", "matter.message.is_control",
521 FT_BOOLEAN
, 8, NULL
, SECURITY_FLAG_IS_CONTROL
,
522 "Whether this is a control message", HFILL
}
524 { &hf_message_flag_extensions
,
525 { "Message Extensions", "matter.message.has_extensions",
526 FT_BOOLEAN
, 8, NULL
, SECURITY_FLAG_HAS_EXTENSIONS
,
527 "Whether message extensions are present", HFILL
}
529 { &hf_message_session_type
,
530 { "Session Type", "matter.message.session_type",
531 FT_UINT8
, BASE_HEX
, VALS(session_type_vals
), SECURITY_FLAG_SESSION_TYPE_MASK
,
532 "The type of session associated with the message", HFILL
}
534 { &hf_message_counter
,
535 { "Message Counter", "matter.message.counter",
536 FT_UINT32
, BASE_HEX
, NULL
, 0,
539 { &hf_message_src_id
,
540 { "Source Node ID", "matter.message.src_id",
541 FT_UINT64
, BASE_HEX
, NULL
, 0,
542 "Unique identifier of the source node", HFILL
}
544 { &hf_message_dest_id
,
545 { "Destination Node ID", "matter.message.dest_id",
546 FT_UINT64
, BASE_HEX
, NULL
, 0,
547 "Unique identifier of the destination node or group", HFILL
}
549 { &hf_message_privacy_header
,
550 { "Encrypted header fields", "matter.message.privacy_header",
551 FT_BYTES
, BASE_NONE
, NULL
, 0,
552 "Headers encrypted with message privacy", HFILL
}
555 { "Payload", "matter.payload",
556 FT_NONE
, BASE_NONE
, NULL
, 0,
557 "Message Payload", HFILL
}
559 { &hf_payload_exchange_flags
,
560 { "Exchange Flags", "matter.payload.exchange_flags",
561 FT_UINT8
, BASE_HEX
, NULL
, 0,
562 "Flags related to the exchange", HFILL
}
564 { &hf_payload_flag_initiator
,
565 { "Initiator", "matter.payload.initiator",
566 FT_BOOLEAN
, 8, NULL
, EXCHANGE_FLAG_IS_INITIATOR
,
567 "Whether the message was sent by the initiator of the exchange", HFILL
}
569 { &hf_payload_flag_ack
,
570 { "Acknowledgement", "matter.payload.ack_msg",
571 FT_BOOLEAN
, 8, NULL
, EXCHANGE_FLAG_ACK_MSG
,
572 "Whether the message is an acknowledgement of a previously-received message", HFILL
}
574 { &hf_payload_flag_reliability
,
575 { "Reliability", "matter.payload.reliability",
576 FT_BOOLEAN
, 8, NULL
, EXCHANGE_FLAG_RELIABILITY
,
577 "Whether the sender wishes to receive an acknowledgement for this message", HFILL
}
579 { &hf_payload_flag_secured_extensions
,
580 { "Secure extensions", "matter.payload.has_secured_ext",
581 FT_BOOLEAN
, 8, NULL
, EXCHANGE_FLAG_HAS_SECURED_EXT
,
582 "Whether this message contains Secured Extensions", HFILL
}
584 { &hf_payload_flag_vendor
,
585 { "Has Vendor ID", "matter.payload.has_vendor_protocol",
586 FT_BOOLEAN
, 8, NULL
, EXCHANGE_FLAG_HAS_VENDOR_PROTO
,
587 "Whether this message contains a protocol vendor ID", HFILL
}
589 { &hf_payload_protocol_opcode
,
590 { "Protocol Opcode", "matter.payload.protocol_opcode",
591 FT_UINT8
, BASE_HEX
, NULL
, 0,
592 "Opcode of the message (depends on Protocol ID)", HFILL
}
594 { &hf_payload_exchange_id
,
595 { "Exchange ID", "matter.payload.exchange_id",
596 FT_UINT16
, BASE_HEX
, NULL
, 0,
597 "The exchange to which the message belongs", HFILL
}
599 { &hf_payload_protocol_vendor_id
,
600 { "Protocol Vendor ID", "matter.payload.protocol_vendor_id",
601 FT_UINT16
, BASE_HEX
, NULL
, 0,
602 "Vendor ID namespace for the protocol ID", HFILL
}
604 { &hf_payload_protocol_id
,
605 { "Protocol ID", "matter.payload.protocol_id",
606 FT_UINT16
, BASE_HEX
, NULL
, 0,
607 "The protocol in which the Protocol Opcode of the message is defined", HFILL
}
609 { &hf_payload_ack_counter
,
610 { "Acknowledged message counter", "matter.payload.ack_counter",
611 FT_UINT32
, BASE_HEX
, NULL
, 0,
612 "The message counter of a previous message that is being acknowledged by this message", HFILL
}
614 { &hf_payload_secured_ext_length
,
615 { "Secured extensions length", "matter.payload.secured_ext.length",
616 FT_UINT16
, BASE_DEC
, NULL
, 0,
617 "Secured extensions payload length, in bytes", HFILL
}
619 { &hf_payload_secured_ext
,
620 { "Secured extensions payload", "matter.payload.secured_ext",
621 FT_BYTES
, BASE_NONE
, NULL
, 0,
624 { &hf_payload_application
,
625 { "Application payload", "matter.payload.application",
626 FT_BYTES
, BASE_NONE
, NULL
, 0,
629 { &hf_matter_tlv_elem
,
630 { "TLV Element", "matter.tlv",
631 FT_NONE
, BASE_NONE
, NULL
, 0x0,
632 "Matter-TLV Element", HFILL
}
634 { &hf_matter_tlv_elem_control
,
635 { "Control Byte", "matter.tlv.control",
636 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
637 "Matter-TLV Control Byte", HFILL
}
639 { &hf_matter_tlv_elem_control_tag_format
,
640 { "Tag Format", "matter.tlv.control.tag",
641 FT_UINT8
, BASE_HEX
, VALS(matter_tlv_tag_format_vals
), 0xE0,
644 { &hf_matter_tlv_elem_control_element_type
,
645 { "Element Type", "matter.tlv.control.element",
646 FT_UINT8
, BASE_HEX
, VALS(matter_tlv_elem_type_vals
), 0x1F,
649 { &hf_matter_tlv_elem_tag
,
650 { "Tag", "matter.tlv.tag",
651 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
654 { &hf_matter_tlv_elem_length
,
655 { "Length", "matter.tlv.length",
656 FT_UINT64
, BASE_DEC
, NULL
, 0x0,
659 { &hf_matter_tlv_elem_value_int
,
660 { "Value", "matter.tlv.value_int",
661 FT_INT64
, BASE_DEC
, NULL
, 0x0,
664 { &hf_matter_tlv_elem_value_uint
,
665 { "Value", "matter.tlv.value_uint",
666 FT_UINT64
, BASE_DEC
, NULL
, 0x0,
669 { &hf_matter_tlv_elem_value_bytes
,
670 { "Value", "matter.tlv.value_bytes",
671 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
676 /* Setup protocol subtree array */
677 static int *ett
[] = {
684 &ett_matter_tlv_control
,
687 static ei_register_info ei
[] = {
688 { &ei_matter_tlv_unsupported_control
,
689 { "matter.tlv.control.unsupported", PI_UNDECODED
, PI_WARN
,
690 "Unsupported Matter-TLV control byte", EXPFILL
}
694 /* Register the protocol name and description */
695 proto_matter
= proto_register_protocol("Matter", "Matter", "matter");
696 matter_handle
= register_dissector("matter", dissect_matter
, proto_matter
);
697 register_dissector("matter.tlv", dissect_matter_tlv
, proto_matter
);
699 /* Required function calls to register the header fields and subtrees */
700 proto_register_field_array(proto_matter
, hf
, array_length(hf
));
701 proto_register_subtree_array(ett
, array_length(ett
));
703 expert_module_t
*expert
= expert_register_protocol(proto_matter
);
704 expert_register_field_array(expert
, ei
, array_length(ei
));
709 proto_reg_handoff_matter(void)
711 dissector_add_for_decode_as("udp.port", matter_handle
);