epan/dissectors/pidl/samr/samr.cnf cnf_dissect_lsa_BinaryString => lsarpc_dissect_str...
[wireshark-sm.git] / epan / dissectors / packet-matter.c
blob9bf715346d1cc812255720c8af697c873f8efe56
1 /* packet-matter.c
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.
25 #include <config.h>
27 #include <epan/expert.h>
28 #include <epan/packet.h>
29 #include <wsutil/array.h>
31 /* Prototypes */
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
95 // Section 4.4.1.2
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
102 // Section 4.4.1.4
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
108 // Section 4.4.3.1
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" },
119 { 0, NULL }
122 static const value_string session_type_vals[] = {
123 { 0, "Unicast Session" },
124 { 1, "Group Session" },
125 { 0, NULL }
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" },
138 { 0, NULL }
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" },
163 { 0x14, "Null" },
164 { 0x15, "Structure" },
165 { 0x16, "Array" },
166 { 0x17, "List" },
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" },
179 { 0, NULL }
182 static int
183 dissect_matter_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *pl_tree);
185 static int
186 dissect_matter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
188 proto_item *ti;
189 proto_tree *matter_tree;
190 uint32_t offset = 0;
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)
201 return 0;
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[] = {
211 &hf_message_version,
212 &hf_message_has_source,
213 &hf_message_dsiz,
214 NULL
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,
221 NULL
224 // Section 4.4.1.2
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);
228 offset += 1;
230 // Section 4.4.1.3
231 proto_tree_add_item_ret_uint(matter_tree, hf_message_session_id, tvb, offset, 2, ENC_LITTLE_ENDIAN, &session_id);
232 offset += 2;
234 // Section 4.4.1.4
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);
238 offset += 1;
240 // decryption of message privacy is not yet supported,
241 // but add an opaque field with the encrypted blob
242 // Section 4.8.3
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;
257 } else {
259 // Section 4.4.1.5
260 proto_tree_add_item(matter_tree, hf_message_counter, tvb, offset, 4, ENC_LITTLE_ENDIAN);
261 offset += 4;
263 // Section 4.4.1.6
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);
266 offset += 8;
268 // Section 4.4.1.7
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);
271 offset += 8;
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);
274 offset += 2;
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);
288 } else {
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);
293 return offset;
296 static int
297 dissect_matter_payload(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *pl_tree)
299 uint32_t offset = 0;
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,
309 NULL
311 // Section 4.4.3.1
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);
314 offset += 1;
316 // Section 4.4.3.2
317 proto_tree_add_item(pl_tree, hf_payload_protocol_opcode, tvb, offset, 1, ENC_LITTLE_ENDIAN);
318 offset += 1;
320 // Section 4.4.3.3
321 proto_tree_add_item(pl_tree, hf_payload_exchange_id, tvb, offset, 2, ENC_LITTLE_ENDIAN);
322 offset += 2;
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);
334 offset += 2;
337 // Section 4.4.3.4
338 proto_tree_add_item(pl_tree, hf_payload_protocol_id, tvb, offset, 2, ENC_LITTLE_ENDIAN);
339 offset += 2;
341 // Section 4.4.3.6
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);
344 offset += 4;
347 // Section 4.4.3.7
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);
351 offset += 2;
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;
358 return offset;
361 // Dissect the Matter-defined TLV encoding.
362 // Appendix A: Tag-length-value (TLV) Encoding Format
363 static int
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);
373 int offset = 0;
375 if (data != NULL)
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);
398 offset += 1;
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)
404 return offset;
406 switch (control_tag_format)
408 case 0: // Anonymous Tag Form (0 octets)
409 break;
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);
412 offset += 1;
413 break;
414 default:
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).
422 uint64_t str_length;
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);
439 offset += size;
440 break;
442 case 0x08: // Boolean False
443 case 0x09: // Boolean True
444 break;
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);
452 offset += size;
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;
455 break;
457 case 0x14: // Null
458 break;
459 case 0x15: // Structure
460 case 0x16: // Array
461 case 0x17: // List
462 offset += dissect_matter_tlv(tvb_new_subset_remaining(tvb, offset), pinfo, tree_element, data);
463 break;
464 default:
465 goto unsupported_control;
468 proto_item_set_len(ti_element, offset - base_offset);
469 continue;
471 unsupported_control:
472 expert_add_info(pinfo, tree_control, &ei_matter_tlv_unsupported_control);
473 proto_item_set_len(ti_element, offset - base_offset);
474 return length;
477 return length;
480 void
481 proto_register_matter(void)
483 static hf_register_info hf[] = {
484 { &hf_message_flags,
485 { "Message Flags", "matter.message.flags",
486 FT_UINT8, BASE_HEX, NULL, 0,
487 NULL, HFILL }
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 }
499 { &hf_message_dsiz,
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,
537 NULL, HFILL }
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 }
554 { &hf_payload,
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,
622 NULL, HFILL }
624 { &hf_payload_application,
625 { "Application payload", "matter.payload.application",
626 FT_BYTES, BASE_NONE, NULL, 0,
627 NULL, HFILL }
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,
642 NULL, HFILL }
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,
647 NULL, HFILL }
649 { &hf_matter_tlv_elem_tag,
650 { "Tag", "matter.tlv.tag",
651 FT_UINT32, BASE_HEX, NULL, 0x0,
652 NULL, HFILL }
654 { &hf_matter_tlv_elem_length,
655 { "Length", "matter.tlv.length",
656 FT_UINT64, BASE_DEC, NULL, 0x0,
657 NULL, HFILL }
659 { &hf_matter_tlv_elem_value_int,
660 { "Value", "matter.tlv.value_int",
661 FT_INT64, BASE_DEC, NULL, 0x0,
662 NULL, HFILL }
664 { &hf_matter_tlv_elem_value_uint,
665 { "Value", "matter.tlv.value_uint",
666 FT_UINT64, BASE_DEC, NULL, 0x0,
667 NULL, HFILL }
669 { &hf_matter_tlv_elem_value_bytes,
670 { "Value", "matter.tlv.value_bytes",
671 FT_BYTES, BASE_NONE, NULL, 0x0,
672 NULL, HFILL }
676 /* Setup protocol subtree array */
677 static int *ett[] = {
678 &ett_matter,
679 &ett_message_flags,
680 &ett_security_flags,
681 &ett_payload,
682 &ett_exchange_flags,
683 &ett_matter_tlv,
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));
708 void
709 proto_reg_handoff_matter(void)
711 dissector_add_for_decode_as("udp.port", matter_handle);