Coverage Report

Created: 2025-12-27 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-matter.c
Line
Count
Source
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>
5
 *
6
 * Wireshark - Network traffic analyzer
7
 * By Gerald Combs <gerald@wireshark.org>
8
 * Copyright 1998 Gerald Combs
9
 *
10
 * SPDX-License-Identifier: GPL-2.0-or-later
11
 */
12
13
/*
14
 * The Matter protocol provides an interoperable application
15
 * layer solution for smart home devices over IPv6.
16
 *
17
 * The specification can be freely requested at:
18
 * https://csa-iot.org/developer-resource/specifications-download-request/
19
 *
20
 * Comments below reference section numbers of the Matter Core Specification R1.0 (22-27349-001).
21
 *
22
 * Matter-TLV dissector is based on Matter Specification Version 1.3.
23
 */
24
25
#include <config.h>
26
27
#include <epan/expert.h>
28
#include <epan/packet.h>
29
#include <wsutil/array.h>
30
31
/* Prototypes */
32
/* (Required to prevent [-Wmissing-prototypes] warnings */
33
void proto_reg_handoff_matter(void);
34
void proto_register_matter(void);
35
36
/* Initialize the protocol and registered fields */
37
static dissector_handle_t matter_handle;
38
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_node_id;
53
static int hf_message_dest_group_id;
54
static int hf_message_privacy_header;
55
56
static int hf_payload;
57
static int hf_payload_mic;
58
static int hf_payload_exchange_flags;
59
static int hf_payload_flag_initiator;
60
static int hf_payload_flag_ack;
61
static int hf_payload_flag_reliability;
62
static int hf_payload_flag_secured_extensions;
63
static int hf_payload_flag_vendor;
64
static int hf_payload_protocol_opcode;
65
static int hf_payload_exchange_id;
66
static int hf_payload_protocol_vendor_id;
67
static int hf_payload_protocol_id;
68
static int hf_payload_ack_counter;
69
static int hf_payload_secured_ext_length;
70
static int hf_payload_secured_ext;
71
static int hf_payload_application;
72
73
static int hf_matter_tlv_elem;
74
static int hf_matter_tlv_elem_control;
75
static int hf_matter_tlv_elem_control_tag_format;
76
static int hf_matter_tlv_elem_control_element_type;
77
static int hf_matter_tlv_elem_tag;
78
static int hf_matter_tlv_elem_length;
79
static int hf_matter_tlv_elem_value_int;
80
static int hf_matter_tlv_elem_value_uint;
81
static int hf_matter_tlv_elem_value_bytes;
82
83
static int ett_matter;
84
static int ett_message_flags;
85
static int ett_security_flags;
86
static int ett_payload;
87
static int ett_exchange_flags;
88
89
static int ett_matter_tlv;
90
static int ett_matter_tlv_control;
91
92
static expert_field ei_matter_tlv_unsupported_control;
93
94
/* message flags + session ID + security flags + counter */
95
0
#define MATTER_MIN_LENGTH 8
96
97
// Section 3.6
98
0
#define CRYPTO_AEAD_MIC_LENGTH 16
99
100
// Section 4.4.1.2
101
14
#define MESSAGE_FLAG_VERSION_MASK       0xF0
102
14
#define MESSAGE_FLAG_HAS_SOURCE         0x04
103
0
#define MESSAGE_FLAG_HAS_DEST_NODE      0x01
104
0
#define MESSAGE_FLAG_HAS_DEST_GROUP     0x02
105
14
#define MESSAGE_FLAG_DSIZ_MASK          0x03
106
107
// Section 4.4.1.4
108
14
#define SECURITY_FLAG_HAS_PRIVACY       0x80
109
14
#define SECURITY_FLAG_IS_CONTROL        0x40
110
14
#define SECURITY_FLAG_HAS_EXTENSIONS    0x20
111
14
#define SECURITY_FLAG_SESSION_TYPE_MASK 0x03
112
0
#define SECURITY_FLAG_SESSION_TYPE_UNICAST 0
113
0
#define SECURITY_FLAG_SESSION_TYPE_GROUP   1
114
115
// Section 4.4.3.1
116
14
#define EXCHANGE_FLAG_IS_INITIATOR      0x01
117
14
#define EXCHANGE_FLAG_ACK_MSG           0x02
118
14
#define EXCHANGE_FLAG_RELIABILITY       0x04
119
14
#define EXCHANGE_FLAG_HAS_SECURED_EXT   0x08
120
14
#define EXCHANGE_FLAG_HAS_VENDOR_PROTO  0x10
121
122
static const value_string dsiz_vals[] = {
123
    { 0, "Not present" },
124
    { MESSAGE_FLAG_HAS_DEST_NODE,  "64-bit Node ID" },
125
    { MESSAGE_FLAG_HAS_DEST_GROUP, "16-bit Group ID" },
126
    { 0, NULL }
127
};
128
129
static const value_string session_type_vals[] = {
130
    { 0, "Unicast Session" },
131
    { 1, "Group Session" },
132
    { 0, NULL }
133
};
134
135
// Appendix 7.2. Tag Control Field
136
static const value_string matter_tlv_tag_format_vals[] = {
137
    { 0, "Anonymous Tag Form, 0 octets" },
138
    { 1, "Context-specific Tag Form, 1 octet" },
139
    { 2, "Common Profile Tag Form, 2 octets" },
140
    { 3, "Common Profile Tag Form, 4 octets" },
141
    { 4, "Implicit Profile Tag Form, 2 octets" },
142
    { 5, "Implicit Profile Tag Form, 4 octets" },
143
    { 6, "Fully-qualified Tag Form, 6 octets" },
144
    { 7, "Fully-qualified Tag Form, 8 octets" },
145
    { 0, NULL }
146
};
147
148
// Appendix 7.1. Element Type Field
149
static const value_string matter_tlv_elem_type_vals[] = {
150
    { 0x00, "Signed Integer, 1-octet value" },
151
    { 0x01, "Signed Integer, 2-octet value" },
152
    { 0x02, "Signed Integer, 4-octet value" },
153
    { 0x03, "Signed Integer, 8-octet value" },
154
    { 0x04, "Unsigned Integer, 1-octet value" },
155
    { 0x05, "Unsigned Integer, 2-octet value" },
156
    { 0x06, "Unsigned Integer, 4-octet value" },
157
    { 0x07, "Unsigned Integer, 8-octet value" },
158
    { 0x08, "Boolean False" },
159
    { 0x09, "Boolean True" },
160
    { 0x0A, "Floating Point Number, 4-octet value" },
161
    { 0x0B, "Floating Point Number, 8-octet value" },
162
    { 0x0C, "UTF-8 String, 1-octet length" },
163
    { 0x0D, "UTF-8 String, 2-octet length" },
164
    { 0x0E, "UTF-8 String, 4-octet length" },
165
    { 0x0F, "UTF-8 String, 8-octet length" },
166
    { 0x10, "Octet String, 1-octet length" },
167
    { 0x11, "Octet String, 2-octet length" },
168
    { 0x12, "Octet String, 4-octet length" },
169
    { 0x13, "Octet String, 8-octet length" },
170
    { 0x14, "Null" },
171
    { 0x15, "Structure" },
172
    { 0x16, "Array" },
173
    { 0x17, "List" },
174
    // XXX: If the Tag Control Field is set to 0x00 (Anonymous Tag), the
175
    //      value of 0x18 means "End of Container". For other Tag Control
176
    //      Field values, the value of 0x18 is reserved.
177
    // TODO: This should be handled in the dissector.
178
    { 0x18, "End of Container" },
179
    { 0x19, "Reserved" },
180
    { 0x1A, "Reserved" },
181
    { 0x1B, "Reserved" },
182
    { 0x1C, "Reserved" },
183
    { 0x1D, "Reserved" },
184
    { 0x1E, "Reserved" },
185
    { 0x1F, "Reserved" },
186
    { 0, NULL }
187
};
188
189
static int
190
dissect_matter_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *pl_tree);
191
192
static int
193
dissect_matter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
194
0
{
195
0
    proto_item *ti;
196
0
    proto_tree *matter_tree;
197
0
    uint32_t    offset = 0;
198
199
    /* info extracted from the packet */
200
0
    bool is_unsecured_session;
201
0
    uint8_t message_flags = 0;
202
0
    uint8_t security_flags = 0;
203
0
    uint8_t message_dsiz = 0;
204
0
    uint8_t message_session_type = 0;
205
0
    uint32_t session_id = 0;
206
207
    /* Check that the packet is long enough for it to belong to us. */
208
0
    if (tvb_reported_length(tvb) < MATTER_MIN_LENGTH)
209
0
        return 0;
210
211
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "Matter");
212
213
    /* create display subtree for the protocol */
214
0
    ti = proto_tree_add_item(tree, proto_matter, tvb, 0, -1, ENC_NA);
215
216
0
    matter_tree = proto_item_add_subtree(ti, ett_matter);
217
218
0
    static int* const message_flag_fields[] = {
219
0
        &hf_message_version,
220
0
        &hf_message_has_source,
221
0
        &hf_message_dsiz,
222
0
        NULL
223
0
    };
224
0
    static int* const message_secflag_fields[] = {
225
0
        &hf_message_flag_privacy,
226
0
        &hf_message_flag_control,
227
0
        &hf_message_flag_extensions,
228
0
        &hf_message_session_type,
229
0
        NULL
230
0
    };
231
232
    // Section 4.4.1.2
233
0
    proto_tree_add_bitmask(matter_tree, tvb, offset, hf_message_flags, ett_message_flags, message_flag_fields, ENC_LITTLE_ENDIAN);
234
0
    message_flags = tvb_get_uint8(tvb, offset);
235
0
    message_dsiz = (message_flags & MESSAGE_FLAG_DSIZ_MASK);
236
0
    offset += 1;
237
238
    // Section 4.4.1.3
239
0
    proto_tree_add_item_ret_uint(matter_tree, hf_message_session_id, tvb, offset, 2, ENC_LITTLE_ENDIAN, &session_id);
240
0
    offset += 2;
241
242
    // Section 4.4.1.4
243
0
    proto_tree_add_bitmask(matter_tree, tvb, offset, hf_message_security_flags, ett_security_flags, message_secflag_fields, ENC_LITTLE_ENDIAN);
244
0
    security_flags = tvb_get_uint8(tvb, offset);
245
0
    message_session_type = (security_flags & SECURITY_FLAG_SESSION_TYPE_MASK);
246
0
    offset += 1;
247
248
    // Section 4.4.1.4: "The Unsecured Session SHALL be indicated
249
    // when both Session Type and Session ID are set to 0."
250
0
    is_unsecured_session = (message_session_type == SECURITY_FLAG_SESSION_TYPE_UNICAST && session_id == 0);
251
252
0
    if (is_unsecured_session)
253
0
        col_set_str(pinfo->cinfo, COL_INFO, "Unsecured Session");
254
0
    else if (message_session_type == SECURITY_FLAG_SESSION_TYPE_UNICAST)
255
0
        col_add_fstr(pinfo->cinfo, COL_INFO, "Unicast Session [0x%04x]", session_id);
256
0
    else if (message_session_type == SECURITY_FLAG_SESSION_TYPE_GROUP)
257
0
        col_add_fstr(pinfo->cinfo, COL_INFO, "Group Session [0x%04x]", session_id);
258
259
    // decryption of message privacy is not yet supported,
260
    // but add an opaque field with the encrypted blob
261
    // Section 4.8.3
262
0
    if (security_flags & SECURITY_FLAG_HAS_PRIVACY) {
263
264
0
        uint32_t privacy_header_length = 4;
265
0
        if (message_flags & MESSAGE_FLAG_HAS_SOURCE) {
266
0
            privacy_header_length += 8;
267
0
        }
268
0
        if (message_dsiz == MESSAGE_FLAG_HAS_DEST_NODE) {
269
0
            privacy_header_length += 8;
270
0
        } else if (message_dsiz == MESSAGE_FLAG_HAS_DEST_GROUP) {
271
0
            privacy_header_length += 2;
272
0
        }
273
0
        proto_tree_add_bytes_format(matter_tree, hf_message_privacy_header, tvb, offset, privacy_header_length, NULL, "Encrypted Headers");
274
0
        offset += privacy_header_length;
275
276
0
    } else {
277
278
        // Section 4.4.1.5
279
0
        unsigned int message_counter;
280
0
        proto_tree_add_item_ret_uint(matter_tree, hf_message_counter, tvb, offset, 4, ENC_LITTLE_ENDIAN, &message_counter);
281
0
        col_append_fstr(pinfo->cinfo, COL_INFO, ": Counter=%u", message_counter);
282
0
        offset += 4;
283
284
        // Section 4.4.1.6
285
0
        if (message_flags & MESSAGE_FLAG_HAS_SOURCE) {
286
0
            uint64_t node_id;
287
0
            proto_tree_add_item_ret_uint64(matter_tree, hf_message_src_id, tvb, offset, 8, ENC_LITTLE_ENDIAN, &node_id);
288
0
            col_append_fstr(pinfo->cinfo, COL_INFO, " Src=0x%016" PRIx64, node_id);
289
0
            offset += 8;
290
0
        }
291
292
        // Section 4.4.1.7
293
0
        if (message_dsiz == MESSAGE_FLAG_HAS_DEST_NODE) {
294
0
            uint64_t node_id;
295
0
            proto_tree_add_item_ret_uint64(matter_tree, hf_message_dest_node_id, tvb, offset, 8, ENC_LITTLE_ENDIAN, &node_id);
296
0
            col_append_fstr(pinfo->cinfo, COL_INFO, " Dest=0x%016" PRIx64, node_id);
297
0
            offset += 8;
298
0
        } else if (message_dsiz == MESSAGE_FLAG_HAS_DEST_GROUP) {
299
0
            unsigned int group_id;
300
0
            proto_tree_add_item_ret_uint(matter_tree, hf_message_dest_group_id, tvb, offset, 2, ENC_LITTLE_ENDIAN, &group_id);
301
0
            col_append_fstr(pinfo->cinfo, COL_INFO, " Group=0x%04x", group_id);
302
0
            offset += 2;
303
0
        }
304
305
0
    }
306
307
0
    if (is_unsecured_session) {
308
0
        proto_item *payload_item = proto_tree_add_none_format(matter_tree, hf_payload, tvb, offset, -1, "Protocol Payload");
309
0
        proto_tree *payload_tree = proto_item_add_subtree(payload_item, ett_payload);
310
0
        tvbuff_t *next_tvb = tvb_new_subset_remaining(tvb, offset);
311
312
0
        offset += dissect_matter_payload(next_tvb, pinfo, payload_tree);
313
0
    } else {
314
        // Secured sessions not yet supported in the dissector.
315
0
        uint32_t payload_length = tvb_reported_length_remaining(tvb, offset) - CRYPTO_AEAD_MIC_LENGTH;
316
0
        proto_tree_add_none_format(matter_tree, hf_payload, tvb, offset, payload_length, "Encrypted Payload (%u bytes)", payload_length);
317
0
        proto_tree_add_item(matter_tree, hf_payload_mic, tvb, offset + payload_length, CRYPTO_AEAD_MIC_LENGTH, ENC_NA);
318
0
    }
319
320
0
    return offset;
321
0
}
322
323
static int
324
dissect_matter_payload(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *pl_tree)
325
0
{
326
0
    uint32_t offset = 0;
327
328
0
    uint8_t exchange_flags = 0;
329
330
0
    static int* const exchange_flag_fields[] = {
331
0
        &hf_payload_flag_initiator,
332
0
        &hf_payload_flag_ack,
333
0
        &hf_payload_flag_reliability,
334
0
        &hf_payload_flag_secured_extensions,
335
0
        &hf_payload_flag_vendor,
336
0
        NULL
337
0
    };
338
    // Section 4.4.3.1
339
0
    proto_tree_add_bitmask(pl_tree, tvb, offset, hf_payload_exchange_flags, ett_exchange_flags, exchange_flag_fields, ENC_LITTLE_ENDIAN);
340
0
    exchange_flags = tvb_get_uint8(tvb, offset);
341
0
    offset += 1;
342
343
    // Section 4.4.3.2
344
0
    proto_tree_add_item(pl_tree, hf_payload_protocol_opcode, tvb, offset, 1, ENC_LITTLE_ENDIAN);
345
0
    offset += 1;
346
347
    // Section 4.4.3.3
348
0
    proto_tree_add_item(pl_tree, hf_payload_exchange_id, tvb, offset, 2, ENC_LITTLE_ENDIAN);
349
0
    offset += 2;
350
351
0
    if (exchange_flags & EXCHANGE_FLAG_HAS_VENDOR_PROTO) {
352
        // NOTE: The Matter specification R1.0 (22-27349) section 4.4 says
353
        // the Vendor ID comes after the Protocol ID. However, the SDK
354
        // implementation expects and produces the vendor ID first and the
355
        // protocol ID afterwards. This was reported, and the maintainers
356
        // declared it a bug in the *specification*, which will be resolved
357
        // in a future version:
358
        // https://github.com/project-chip/connectedhomeip/issues/25003
359
        // So we parse Vendor ID first, contrary to the current spec.
360
0
        proto_tree_add_item(pl_tree, hf_payload_protocol_vendor_id, tvb, offset, 2, ENC_LITTLE_ENDIAN);
361
0
        offset += 2;
362
0
    }
363
364
    // Section 4.4.3.4
365
0
    proto_tree_add_item(pl_tree, hf_payload_protocol_id, tvb, offset, 2, ENC_LITTLE_ENDIAN);
366
0
    offset += 2;
367
368
    // Section 4.4.3.6
369
0
    if (exchange_flags & EXCHANGE_FLAG_ACK_MSG) {
370
0
        unsigned int ack_counter;
371
0
        proto_tree_add_item_ret_uint(pl_tree, hf_payload_ack_counter, tvb, offset, 4, ENC_LITTLE_ENDIAN, &ack_counter);
372
0
        col_append_fstr(pinfo->cinfo, COL_INFO, " AckCounter=%u", ack_counter);
373
0
        offset += 4;
374
0
    }
375
376
    // Section 4.4.3.7
377
0
    if (exchange_flags & EXCHANGE_FLAG_HAS_SECURED_EXT) {
378
0
        uint32_t secured_ext_len = 0;
379
0
        proto_tree_add_item_ret_uint(pl_tree, hf_payload_secured_ext_length, tvb, offset, 2, ENC_LITTLE_ENDIAN, &secured_ext_len);
380
0
        offset += 2;
381
0
        proto_tree_add_item(pl_tree, hf_payload_secured_ext, tvb, offset, secured_ext_len, ENC_NA);
382
0
        offset += secured_ext_len;
383
0
    }
384
0
    uint32_t application_length = tvb_reported_length_remaining(tvb, offset);
385
0
    proto_tree_add_bytes_format(pl_tree, hf_payload_application, tvb, offset, application_length, NULL, "Application payload (%u bytes)", application_length);
386
0
    offset += application_length;
387
0
    return offset;
388
0
}
389
390
// Dissect the Matter-defined TLV encoding.
391
// Appendix A: Tag-length-value (TLV) Encoding Format
392
static int
393
// NOLINTNEXTLINE(misc-no-recursion)
394
dissect_matter_tlv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
395
0
{
396
    // For signed and unsigned integer types and for UTF-8 and octet strings,
397
    // the length is encoded in the lowest 2 bits of the control byte.
398
0
    static const int elem_sizes[] = { 1, 2, 4, 8 };
399
400
0
    int matter_tlv_elem_tag = hf_matter_tlv_elem_tag;
401
0
    int length = tvb_reported_length_remaining(tvb, 0);
402
0
    int offset = 0;
403
404
0
    if (data != NULL)
405
        // Use caller-provided tag field.
406
0
        matter_tlv_elem_tag = *((int *)data);
407
408
0
    while (offset < length) {
409
410
        // The new element is created with initial length set to 1 which accounts
411
        // for the control byte (tag format and element type). The length will be
412
        // updated once the element is fully dissected.
413
0
        proto_item *ti_element = proto_tree_add_item(tree, hf_matter_tlv_elem, tvb, offset, 1, ENC_NA);
414
0
        proto_tree *tree_element = proto_item_add_subtree(ti_element, ett_matter_tlv);
415
0
        int base_offset = offset;
416
417
0
        uint32_t control_tag_format = 0;
418
0
        uint32_t control_element = 0;
419
420
0
        proto_item *ti_control = proto_tree_add_item(tree_element, hf_matter_tlv_elem_control, tvb, offset, 1, ENC_NA);
421
0
        proto_tree *tree_control = proto_item_add_subtree(ti_control, ett_matter_tlv_control);
422
        // The tag format is determined by the upper 3 bits of the control byte.
423
0
        proto_tree_add_item_ret_uint(tree_control, hf_matter_tlv_elem_control_tag_format, tvb, offset, 1, ENC_NA, &control_tag_format);
424
        // The element type is determined by the lower 5 bits of the control byte.
425
0
        proto_tree_add_item_ret_uint(tree_control, hf_matter_tlv_elem_control_element_type, tvb, offset, 1, ENC_NA, &control_element);
426
427
0
        offset += 1;
428
429
0
        proto_item_append_text(ti_element, ": %s", val_to_str_const(control_element, matter_tlv_elem_type_vals, "Unknown"));
430
431
        // The control byte 0x18 means "End of Container".
432
0
        if (control_tag_format == 0 && control_element == 0x18)
433
0
            return offset;
434
435
0
        switch (control_tag_format)
436
0
        {
437
0
        case 0: // Anonymous Tag Form (0 octets)
438
0
            break;
439
0
        case 1: // Context-specific Tag Form (1 octet)
440
0
            proto_tree_add_item(tree_element, matter_tlv_elem_tag, tvb, offset, 1, ENC_NA);
441
0
            offset += 1;
442
0
            break;
443
0
        default:
444
0
            goto unsupported_control;
445
0
        }
446
447
        // The string length might be encoded on 1, 2, 4 or 8 octets. In theory,
448
        // the length can be up to 2^64 - 1 bytes, but in practice, it should be
449
        // limited to a reasonable value (it should be safe to assume that the
450
        // length will not exceed 2^16 - 1 bytes).
451
0
        uint64_t str_length;
452
453
0
        switch (control_element)
454
0
        {
455
0
        case 0x00: // Signed Integer, 1-octet value
456
0
        case 0x01: // Signed Integer, 2-octet value
457
0
        case 0x02: // Signed Integer, 4-octet value
458
0
        case 0x03: // Signed Integer, 8-octet value
459
0
        case 0x04: // Unsigned Integer, 1-octet value
460
0
        case 0x05: // Unsigned Integer, 2-octet value
461
0
        case 0x06: // Unsigned Integer, 4-octet value
462
0
        case 0x07: // Unsigned Integer, 8-octet value
463
0
        {
464
            // Integer type (signed or unsigned) is encoded in the 3rd bit of the control element.
465
0
            int hf = (control_element & 0x04) ? hf_matter_tlv_elem_value_uint : hf_matter_tlv_elem_value_int;
466
0
            int size = elem_sizes[control_element & 0x03];
467
0
            proto_tree_add_item(tree_element, hf, tvb, offset, size, ENC_LITTLE_ENDIAN);
468
0
            offset += size;
469
0
            break;
470
0
        }
471
0
        case 0x08: // Boolean False
472
0
        case 0x09: // Boolean True
473
0
            break;
474
0
        case 0x10: // Octet String (1-octet length)
475
0
        case 0x11: // Octet String (2-octet length)
476
0
        case 0x12: // Octet String (4-octet length)
477
0
        case 0x13: // Octet String (8-octet length)
478
0
        {
479
0
            int size = elem_sizes[control_element & 0x03];
480
0
            proto_tree_add_item_ret_uint64(tree_element, hf_matter_tlv_elem_length, tvb, offset, size, ENC_LITTLE_ENDIAN, &str_length);
481
0
            offset += size;
482
0
            proto_tree_add_item(tree_element, hf_matter_tlv_elem_value_bytes, tvb, offset, (int)str_length, ENC_NA);
483
0
            offset += (int)str_length;
484
0
            break;
485
0
        }
486
0
        case 0x14: // Null
487
0
            break;
488
0
        case 0x15: // Structure
489
0
        case 0x16: // Array
490
0
        case 0x17: // List
491
0
            offset += dissect_matter_tlv(tvb_new_subset_remaining(tvb, offset), pinfo, tree_element, data);
492
0
            break;
493
0
        default:
494
0
            goto unsupported_control;
495
0
        }
496
497
0
        proto_item_set_len(ti_element, offset - base_offset);
498
0
        continue;
499
500
0
unsupported_control:
501
0
        expert_add_info(pinfo, tree_control, &ei_matter_tlv_unsupported_control);
502
0
        proto_item_set_len(ti_element, offset - base_offset);
503
0
        return length;
504
0
    }
505
506
0
    return length;
507
0
}
508
509
void
510
proto_register_matter(void)
511
14
{
512
14
    static hf_register_info hf[] = {
513
14
        { &hf_message_flags,
514
14
          { "Message Flags", "matter.message.flags",
515
14
            FT_UINT8, BASE_HEX, NULL, 0,
516
14
            NULL, HFILL }
517
14
        },
518
14
        { &hf_message_version,
519
14
          { "Version", "matter.message.version",
520
14
            FT_UINT8, BASE_DEC, NULL, MESSAGE_FLAG_VERSION_MASK,
521
14
            "Message format version", HFILL }
522
14
        },
523
14
        { &hf_message_has_source,
524
14
          { "Has Source ID", "matter.message.has_source_id",
525
14
            FT_BOOLEAN, 8, NULL, MESSAGE_FLAG_HAS_SOURCE,
526
14
            "Source ID field is present", HFILL }
527
14
        },
528
14
        { &hf_message_dsiz,
529
14
          { "Destination ID Type", "matter.message.dsiz",
530
14
            FT_UINT8, BASE_DEC, VALS(dsiz_vals), MESSAGE_FLAG_DSIZ_MASK,
531
14
            "Size and meaning of the Destination Node ID field", HFILL }
532
14
        },
533
14
        { &hf_message_session_id,
534
14
          { "Session ID", "matter.message.session_id",
535
14
            FT_UINT16, BASE_HEX, NULL, 0,
536
14
            "The session associated with this message", HFILL }
537
14
        },
538
14
        { &hf_message_security_flags,
539
14
          { "Security Flags", "matter.message.security_flags",
540
14
            FT_UINT8, BASE_HEX, NULL, 0,
541
14
            "Message security flags", HFILL }
542
14
        },
543
14
        { &hf_message_flag_privacy,
544
14
          { "Privacy", "matter.message.has_privacy",
545
14
            FT_BOOLEAN, 8, NULL, SECURITY_FLAG_HAS_PRIVACY,
546
14
            "Whether the message is encoded with privacy enhancements", HFILL }
547
14
        },
548
14
        { &hf_message_flag_control,
549
14
          { "Control", "matter.message.is_control",
550
14
            FT_BOOLEAN, 8, NULL, SECURITY_FLAG_IS_CONTROL,
551
14
            "Whether this is a control message", HFILL }
552
14
        },
553
14
        { &hf_message_flag_extensions,
554
14
          { "Message Extensions", "matter.message.has_extensions",
555
14
            FT_BOOLEAN, 8, NULL, SECURITY_FLAG_HAS_EXTENSIONS,
556
14
            "Whether message extensions are present", HFILL }
557
14
        },
558
14
        { &hf_message_session_type,
559
14
          { "Session Type", "matter.message.session_type",
560
14
            FT_UINT8, BASE_HEX, VALS(session_type_vals), SECURITY_FLAG_SESSION_TYPE_MASK,
561
14
            "The type of session associated with the message", HFILL }
562
14
        },
563
14
        { &hf_message_counter,
564
14
          { "Message Counter", "matter.message.counter",
565
14
            FT_UINT32, BASE_DEC, NULL, 0,
566
14
            NULL, HFILL }
567
14
        },
568
14
        { &hf_message_src_id,
569
14
          { "Source Node ID", "matter.message.src_id",
570
14
            FT_UINT64, BASE_HEX, NULL, 0,
571
14
            "Unique identifier of the source node", HFILL }
572
14
        },
573
14
        { &hf_message_dest_node_id,
574
14
          { "Destination Node ID", "matter.message.dest_node_id",
575
14
            FT_UINT64, BASE_HEX, NULL, 0,
576
14
            "Unique identifier of the destination node", HFILL }
577
14
        },
578
14
        { &hf_message_dest_group_id,
579
14
          { "Destination Group ID", "matter.message.dest_group_id",
580
14
            FT_UINT16, BASE_HEX, NULL, 0,
581
14
            "Unique identifier of the destination group", HFILL }
582
14
        },
583
14
        { &hf_message_privacy_header,
584
14
          { "Encrypted header fields", "matter.message.privacy_header",
585
14
            FT_BYTES, BASE_NONE, NULL, 0,
586
14
            "Headers encrypted with message privacy", HFILL }
587
14
        },
588
14
        { &hf_payload,
589
14
          { "Payload", "matter.payload",
590
14
            FT_NONE, BASE_NONE, NULL, 0,
591
14
            "Message Payload", HFILL }
592
14
        },
593
14
        { &hf_payload_mic,
594
14
          { "Integrity Check", "matter.payload.mic",
595
14
            FT_BYTES, BASE_NONE, NULL, 0,
596
14
            "Message Integrity Check (MIC) for the encrypted payload", HFILL }
597
14
        },
598
14
        { &hf_payload_exchange_flags,
599
14
          { "Exchange Flags", "matter.payload.exchange_flags",
600
14
            FT_UINT8, BASE_HEX, NULL, 0,
601
14
            "Flags related to the exchange", HFILL }
602
14
        },
603
14
        { &hf_payload_flag_initiator,
604
14
          { "Initiator", "matter.payload.initiator",
605
14
            FT_BOOLEAN, 8, NULL, EXCHANGE_FLAG_IS_INITIATOR,
606
14
            "Whether the message was sent by the initiator of the exchange", HFILL }
607
14
        },
608
14
        { &hf_payload_flag_ack,
609
14
          { "Acknowledgement", "matter.payload.ack_msg",
610
14
            FT_BOOLEAN, 8, NULL, EXCHANGE_FLAG_ACK_MSG,
611
14
            "Whether the message is an acknowledgement of a previously-received message", HFILL }
612
14
        },
613
14
        { &hf_payload_flag_reliability,
614
14
          { "Reliability", "matter.payload.reliability",
615
14
            FT_BOOLEAN, 8, NULL, EXCHANGE_FLAG_RELIABILITY,
616
14
            "Whether the sender wishes to receive an acknowledgement for this message", HFILL }
617
14
        },
618
14
        { &hf_payload_flag_secured_extensions,
619
14
          { "Secure extensions", "matter.payload.has_secured_ext",
620
14
            FT_BOOLEAN, 8, NULL, EXCHANGE_FLAG_HAS_SECURED_EXT,
621
14
            "Whether this message contains Secured Extensions", HFILL }
622
14
        },
623
14
        { &hf_payload_flag_vendor,
624
14
          { "Has Vendor ID", "matter.payload.has_vendor_protocol",
625
14
            FT_BOOLEAN, 8, NULL, EXCHANGE_FLAG_HAS_VENDOR_PROTO,
626
14
            "Whether this message contains a protocol vendor ID", HFILL }
627
14
        },
628
14
        { &hf_payload_protocol_opcode,
629
14
          { "Protocol Opcode", "matter.payload.protocol_opcode",
630
14
            FT_UINT8, BASE_HEX, NULL, 0,
631
14
            "Opcode of the message (depends on Protocol ID)", HFILL }
632
14
        },
633
14
        { &hf_payload_exchange_id,
634
14
          { "Exchange ID", "matter.payload.exchange_id",
635
14
            FT_UINT16, BASE_HEX, NULL, 0,
636
14
            "The exchange to which the message belongs", HFILL }
637
14
        },
638
14
        { &hf_payload_protocol_vendor_id,
639
14
          { "Protocol Vendor ID", "matter.payload.protocol_vendor_id",
640
14
            FT_UINT16, BASE_HEX, NULL, 0,
641
14
            "Vendor ID namespace for the protocol ID", HFILL }
642
14
        },
643
14
        { &hf_payload_protocol_id,
644
14
          { "Protocol ID", "matter.payload.protocol_id",
645
14
            FT_UINT16, BASE_HEX, NULL, 0,
646
14
            "The protocol in which the Protocol Opcode of the message is defined", HFILL }
647
14
        },
648
14
        { &hf_payload_ack_counter,
649
14
          { "Acknowledged message counter", "matter.payload.ack_counter",
650
14
            FT_UINT32, BASE_DEC, NULL, 0,
651
14
            "The message counter of a previous message that is being acknowledged by this message", HFILL }
652
14
        },
653
14
        { &hf_payload_secured_ext_length,
654
14
          { "Secured extensions length", "matter.payload.secured_ext.length",
655
14
            FT_UINT16, BASE_DEC, NULL, 0,
656
14
            "Secured extensions payload length, in bytes", HFILL }
657
14
        },
658
14
        { &hf_payload_secured_ext,
659
14
          { "Secured extensions payload", "matter.payload.secured_ext",
660
14
            FT_BYTES, BASE_NONE, NULL, 0,
661
14
            NULL, HFILL }
662
14
        },
663
14
        { &hf_payload_application,
664
14
          { "Application payload", "matter.payload.application",
665
14
            FT_BYTES, BASE_NONE, NULL, 0,
666
14
            NULL, HFILL }
667
14
        },
668
14
        { &hf_matter_tlv_elem,
669
14
          { "TLV Element", "matter.tlv",
670
14
            FT_NONE, BASE_NONE, NULL, 0x0,
671
14
            "Matter-TLV Element", HFILL }
672
14
        },
673
14
        { &hf_matter_tlv_elem_control,
674
14
          { "Control Byte", "matter.tlv.control",
675
14
            FT_UINT8, BASE_HEX, NULL, 0x0,
676
14
            "Matter-TLV Control Byte", HFILL }
677
14
        },
678
14
        { &hf_matter_tlv_elem_control_tag_format,
679
14
          { "Tag Format", "matter.tlv.control.tag",
680
14
            FT_UINT8, BASE_HEX, VALS(matter_tlv_tag_format_vals), 0xE0,
681
14
            NULL, HFILL }
682
14
        },
683
14
        { &hf_matter_tlv_elem_control_element_type,
684
14
          { "Element Type", "matter.tlv.control.element",
685
14
            FT_UINT8, BASE_HEX, VALS(matter_tlv_elem_type_vals), 0x1F,
686
14
            NULL, HFILL }
687
14
        },
688
14
        { &hf_matter_tlv_elem_tag,
689
14
          { "Tag", "matter.tlv.tag",
690
14
            FT_UINT32, BASE_HEX, NULL, 0x0,
691
14
            NULL, HFILL }
692
14
        },
693
14
        { &hf_matter_tlv_elem_length,
694
14
          { "Length", "matter.tlv.length",
695
14
            FT_UINT64, BASE_DEC, NULL, 0x0,
696
14
            NULL, HFILL }
697
14
        },
698
14
        { &hf_matter_tlv_elem_value_int,
699
14
          { "Value", "matter.tlv.value_int",
700
14
            FT_INT64, BASE_DEC, NULL, 0x0,
701
14
            NULL, HFILL }
702
14
        },
703
14
        { &hf_matter_tlv_elem_value_uint,
704
14
          { "Value", "matter.tlv.value_uint",
705
14
            FT_UINT64, BASE_DEC, NULL, 0x0,
706
14
            NULL, HFILL }
707
14
        },
708
14
        { &hf_matter_tlv_elem_value_bytes,
709
14
          { "Value", "matter.tlv.value_bytes",
710
14
            FT_BYTES, BASE_NONE, NULL, 0x0,
711
14
            NULL, HFILL }
712
14
        },
713
14
    };
714
715
    /* Setup protocol subtree array */
716
14
    static int *ett[] = {
717
14
        &ett_matter,
718
14
        &ett_message_flags,
719
14
        &ett_security_flags,
720
14
        &ett_payload,
721
14
        &ett_exchange_flags,
722
14
        &ett_matter_tlv,
723
14
        &ett_matter_tlv_control,
724
14
    };
725
726
14
    static ei_register_info ei[] = {
727
14
        { &ei_matter_tlv_unsupported_control,
728
14
          { "matter.tlv.control.unsupported", PI_UNDECODED, PI_WARN,
729
14
            "Unsupported Matter-TLV control byte", EXPFILL }
730
14
        },
731
14
    };
732
733
    /* Register the protocol name and description */
734
14
    proto_matter = proto_register_protocol("Matter", "Matter", "matter");
735
14
    matter_handle = register_dissector("matter", dissect_matter, proto_matter);
736
14
    register_dissector("matter.tlv", dissect_matter_tlv, proto_matter);
737
738
    /* Required function calls to register the header fields and subtrees */
739
14
    proto_register_field_array(proto_matter, hf, array_length(hf));
740
14
    proto_register_subtree_array(ett, array_length(ett));
741
742
14
    expert_module_t *expert = expert_register_protocol(proto_matter);
743
14
    expert_register_field_array(expert, ei, array_length(ei));
744
745
14
}
746
747
void
748
proto_reg_handoff_matter(void)
749
14
{
750
14
    dissector_add_for_decode_as("udp.port", matter_handle);
751
14
}