Coverage Report

Created: 2026-08-14 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-s101.c
Line
Count
Source
1
/* packet-s101.c
2
 * Routines for S101 dissection
3
 * Copyright 2018, Gilles Dufour <dufour.gilles@gmail.com>
4
 *
5
 * Wireshark - Network traffic analyzer
6
 * By Gerald Combs <gerald@wireshark.org>
7
 * Copyright 1998 Gerald Combs
8
 *
9
 * SPDX-License-Identifier: GPL-2.0-or-later
10
 */
11
12
/*
13
 * This Dissector will dissect S101 frames used by Lawo Ember Plus protocol.
14
 * https://github.com/Lawo/ember-plus/
15
 */
16
17
#include <config.h>
18
19
#include <epan/packet.h>   /* Should be first Wireshark include (other than config.h) */
20
#include <epan/prefs.h>
21
#include <epan/reassemble.h>
22
#include <wsutil/crc16.h>
23
#include <epan/expert.h>
24
25
26
0
#define S101_HEADER_DATA_LENGTH 9
27
6
#define S101_BOF 0xFE
28
0
#define S101_EOF 0xFF
29
0
#define S101_CE  0xFD
30
0
#define S101_XOR 0x20
31
6
#define S101_INV 0xF8
32
0
#define S101_SLOT 0x00
33
0
#define S101_MSG_EMBER 0x0E
34
0
#define S101_CMD_EMBER 0x00
35
#define S101_CMD_KEEPALIVE_REQ 0x01
36
0
#define S101_CMD_KEEPALIVE_RESP 0x02
37
0
#define S101_VERSION 0x01
38
0
#define FLAG_SINGLE_PACKET 0xC0
39
0
#define FLAG_FIRST_MULTI_PACKET 0x80
40
0
#define FLAG_LAST_MULTI_PACKET 0x40
41
#define FLAG_EMPTY_PACKET 0x20
42
0
#define FLAG_MULTI_PACKET 0x00
43
0
#define S101_DTD_GLOW 0x01
44
#define S101_DTD_VERSION_MAJOR 0x02
45
#define S101_DTD_VERSION_MINOR 0x1F
46
0
#define S101_VALID_CRC 0xF0B8
47
0
#define APP_BYTES_LEN 2
48
49
static int hf_S101_frame_format;
50
static int hf_S101_length_size;
51
static int hf_S101_message_length;
52
static int hf_S101_slot;
53
static int hf_S101_message_type;
54
static int hf_S101_cmd_type;
55
static int hf_S101_version;
56
static int hf_S101_flags;
57
static int hf_S101_dtd_type;
58
static int hf_S101_app_bytes_len;
59
static int hf_S101_dtd_minor_ver;
60
static int hf_S101_dtd_major_ver;
61
static int hf_S101_crc;
62
static int hf_S101_crc_status;
63
static int hf_S101_eof;
64
static int hf_S101_error;
65
66
static dissector_handle_t S101_handle;
67
static dissector_handle_t glow_handle;
68
static reassembly_table s101_data_reassembly_table;
69
70
typedef struct _s101_fragment_t {
71
    uint32_t id;
72
    int offset;
73
} s101_fragment_t;
74
75
/* Prototypes */
76
/* (Required to prevent [-Wmissing-prototypes] warnings */
77
void proto_reg_handoff_S101(void);
78
void proto_register_S101(void);
79
static tvbuff_t *decode_s101_escaped_buffer(tvbuff_t *tvb, packet_info *pinfo, int *offset, uint16_t *crc);
80
static uint32_t get_fragment_pdu_id(packet_info *pinfo);
81
static s101_fragment_t* new_fragment_info(packet_info *pinfo);
82
static void display_expert_info(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset, int len);
83
84
/* Initialize the protocol and registered fields */
85
static int proto_S101;
86
87
/* Real port preferences should generally default to 0 unless there is an
88
 * IANA-registered (or equivalent) port for your protocol. */
89
16
#define S101_TCP_PORT 9000 /* Not IANA-registered */
90
91
/* Initialize the subtree pointers */
92
static int ett_S101;
93
static int ett_decoding_error;
94
95
8
#define S101_MIN_LENGTH 5
96
97
static int hf_msg_fragments;
98
static int hf_msg_fragment;
99
static int hf_msg_fragment_overlap;
100
static int hf_msg_fragment_overlap_conflicts;
101
static int hf_msg_fragment_multiple_tails;
102
static int hf_msg_fragment_too_long_fragment;
103
static int hf_msg_fragment_error;
104
static int hf_msg_fragment_count;
105
static int hf_msg_reassembled_in;
106
static int hf_msg_reassembled_length;
107
static int hf_msg_reassembled_data;
108
109
110
static expert_field ei_s101_failed_reassembly;
111
112
static int ett_msg_fragment;
113
static int ett_msg_fragments;
114
115
static const fragment_items msg_frag_items = {
116
    /* Fragment subtrees */
117
    &ett_msg_fragment,
118
    &ett_msg_fragments,
119
    /* Fragment fields */
120
    &hf_msg_fragments,
121
    &hf_msg_fragment,
122
    &hf_msg_fragment_overlap,
123
    &hf_msg_fragment_overlap_conflicts,
124
    &hf_msg_fragment_multiple_tails,
125
    &hf_msg_fragment_too_long_fragment,
126
    &hf_msg_fragment_error,
127
    &hf_msg_fragment_count,
128
    /* Reassembled in field */
129
    &hf_msg_reassembled_in,
130
    /* Reassembled length field */
131
    &hf_msg_reassembled_length,
132
    &hf_msg_reassembled_data,
133
    /* Tag */
134
    "Message fragments"
135
};
136
137
/*
138
 Create a unique id to link fragments together.
139
 This is a 4 bytes value:
140
 | SRCPORT (16) | SRC_ADDRESS (16) |
141
 SRC_ADDRESS is last 2 bytes of the src address.
142
 */
143
0
static uint32_t get_fragment_pdu_id(packet_info *pinfo) {
144
0
    uint32_t id = pinfo->srcport << 16;
145
0
    const uint8_t *data = (const uint8_t*)pinfo->src.data;
146
0
    if (pinfo->src.len >= 2) {
147
0
        id =  id + (((uint32_t)data[pinfo->src.len - 2]) << 8) + (uint32_t)data[pinfo->src.len - 1];
148
0
    }
149
0
    return id;
150
0
}
151
152
static wmem_map_t* s101_fragment_info_hash;
153
154
0
static s101_fragment_t* new_fragment_info(packet_info *pinfo) {
155
0
    s101_fragment_t* fi = wmem_new(wmem_file_scope(), s101_fragment_t);
156
0
    if (NULL == fi) { return fi; }
157
0
    fi->id = pinfo->num;
158
0
    fi->offset = 0;
159
0
    return fi;
160
0
}
161
162
/* Get 1 byte
163
 If byte escaped, get the unescaped value
164
 */
165
0
static uint8_t get_byte(tvbuff_t *tvb, int *offset, uint16_t *crc) {
166
0
    uint8_t b = tvb_get_uint8(tvb, *offset);
167
0
    *crc = crc16_ccitt_seed(&b, 1, *crc) ^ 0xFFFF;
168
0
    *offset = *offset + 1;
169
0
    if (b == S101_CE) {
170
0
        b = tvb_get_uint8(tvb, *offset);
171
0
        *crc = crc16_ccitt_seed(&b, 1, *crc) ^ 0xFFFF;
172
0
        *offset = *offset + 1;
173
0
        return (b ^ S101_XOR);
174
0
    } else {
175
0
        return b;
176
0
    }
177
0
}
178
179
180
static const value_string frame_format_vs[] = {
181
    { S101_BOF , "Escaped Frame" },
182
    { S101_INV , "UnEscaped Frame"},
183
    { 0, NULL}
184
};
185
186
static const value_string message_type_vs[] = {
187
    { S101_MSG_EMBER , "Ember" },
188
    { 0, NULL}
189
};
190
191
static const value_string command_type_vs[] = {
192
    { S101_CMD_EMBER , "Ember Command" },
193
    { S101_CMD_KEEPALIVE_REQ , "Keepalive Request" },
194
    { S101_CMD_KEEPALIVE_RESP , "Keepalive Response" },
195
    { 0, NULL}
196
};
197
198
static const value_string flags_vs[] = {
199
    { FLAG_SINGLE_PACKET , "Single Packet" },
200
    { FLAG_EMPTY_PACKET , "Empty Packet" },
201
    { FLAG_MULTI_PACKET , "Multi Packet" },
202
    { FLAG_LAST_MULTI_PACKET , "Last Packet" },
203
    { FLAG_FIRST_MULTI_PACKET , "First Packet" },
204
    { 0, NULL}
205
};
206
207
static const value_string dtd_type_vs[] = {
208
    { S101_DTD_GLOW , "DTD Glow" },
209
    { 0, NULL}
210
};
211
212
213
214
static void
215
0
display_expert_info(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset, int len) {
216
0
    proto_item* pi;
217
0
    proto_tree *error_tree;
218
219
0
    error_tree = proto_tree_add_subtree(tree, tvb, offset, len,
220
0
                           ett_decoding_error, &pi, "S101 Error");
221
222
0
    pi = proto_tree_add_string_format_value(
223
0
            error_tree, hf_S101_error, tvb, offset, len, "s101_error",
224
0
            "reassembly error");
225
226
0
    expert_add_info(pinfo, pi, &ei_s101_failed_reassembly);
227
0
}
228
229
/*
230
  Check s101 packet header format.
231
 If not valid, return 0.
232
 If valid, extract all header parameters and return 1.
233
 If variant1, set msgLength to zero.  We will have to search the end of frame.
234
 If variant2, the msgLength contains the msgLength in bytes 0-6 and byte 7 is the number of bytes.
235
 */
236
static int
237
find_s101_packet_header(tvbuff_t *tvb, int* offset, uint8_t *start, uint8_t *slot, uint8_t *message, uint8_t *version, uint8_t *dtd, uint8_t *command,
238
                           uint8_t *flags, uint8_t* app_bytes, uint64_t *msgLength, uint16_t *crc)
239
6
{
240
6
    uint8_t app_bytes_len = 0;
241
6
    int i;
242
243
6
    *start = tvb_get_uint8(tvb, *offset); // no CRC and no escaping on first bytes.
244
6
    *offset = *offset + 1;
245
6
    if (*start == S101_INV) { // Variant 2 of header - unescaped data
246
        //Read the frame length
247
0
        app_bytes_len = tvb_get_uint8(tvb, *offset) & 0x7;
248
0
        *offset = *offset + 1;
249
250
0
        if (app_bytes_len > 1) {
251
0
            *msgLength = tvb_get_bits64 (tvb, *offset, app_bytes_len * 8, ENC_BIG_ENDIAN);
252
0
            *msgLength = *msgLength + (((uint64_t)app_bytes_len) << 56);
253
0
            *offset = app_bytes_len;
254
0
        }
255
0
    }
256
6
    else if (*start != S101_BOF) {
257
        // IF NOT Beginning of Frame - variant 1 - escaped data
258
6
        return 0;
259
6
    }
260
0
    else {
261
0
        *msgLength = 0;
262
0
    }
263
264
0
    *slot = get_byte(tvb, offset, crc);
265
0
    *message = get_byte(tvb, offset, crc);
266
0
    *command = get_byte(tvb, offset, crc);
267
0
    *version = get_byte(tvb, offset, crc);
268
269
0
    if (*command == S101_CMD_EMBER) {
270
0
        *flags = get_byte(tvb, offset, crc);
271
0
        *dtd = get_byte(tvb, offset, crc);
272
0
        app_bytes_len = get_byte(tvb, offset, crc);
273
0
    }
274
0
    if ((S101_SLOT != *slot) ||
275
0
        (S101_MSG_EMBER != *message) || (*command > S101_CMD_KEEPALIVE_RESP) ||
276
0
        (S101_VERSION != *version ) ||
277
0
        ((*command == S101_CMD_EMBER) &&
278
0
         ((*flags & 0xF) || (S101_DTD_GLOW != *dtd) || (APP_BYTES_LEN != app_bytes_len)))) {
279
0
        return 0;
280
0
    }
281
0
    if (*command == S101_CMD_EMBER) {
282
0
        for(i = 0; i < APP_BYTES_LEN; i++) {
283
0
            app_bytes[i] = get_byte(tvb, offset, crc);
284
0
        }
285
0
    }
286
0
    return 1;
287
0
}
288
289
static tvbuff_t *
290
0
decode_s101_escaped_buffer(tvbuff_t *tvb, packet_info *pinfo, int *offset, uint16_t *crc) {
291
0
    tvbuff_t *next_tvb;
292
0
    int len;
293
0
    int i;
294
0
    unsigned char *decoded_buffer;
295
0
    uint8_t b;
296
297
0
    len = tvb_captured_length(tvb);
298
0
    if (len <= 0) {
299
0
        return tvb;
300
0
    }
301
0
    decoded_buffer = (unsigned char*)wmem_alloc(pinfo->pool, len);
302
0
    if (decoded_buffer == NULL) {
303
0
        return tvb;
304
0
    }
305
306
0
    for(i = 0; *offset < len; ) {
307
0
        b = tvb_get_uint8(tvb, *offset);
308
0
        *offset = *offset + 1;
309
0
        if (b == S101_CE) {
310
            // Escaped Byte
311
0
            b = tvb_get_uint8(tvb, *offset);
312
0
            *offset = *offset + 1;
313
0
            b = (b ^ S101_XOR);
314
0
            decoded_buffer[i++] = b;
315
0
        }
316
0
        else {
317
0
            decoded_buffer[i] = b;
318
0
            if (b == S101_EOF) { // End of Frame
319
                // let's remove the CRC and the EOF
320
0
                if (i > 2) {
321
0
                    i -= 2;
322
0
                }
323
0
                break;
324
0
            }
325
0
            i++;
326
0
        }
327
0
        *crc = crc16_ccitt_seed(&b, 1, *crc) ^ 0xFFFF;
328
0
    }
329
330
0
    next_tvb = tvb_new_child_real_data(tvb, decoded_buffer, i, i);
331
0
    add_new_data_source(pinfo, next_tvb, "Decoded Data");
332
0
    return next_tvb;
333
0
}
334
335
336
337
/* Code to actually dissect the packets */
338
static int
339
dissect_S101(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
340
        void *data _U_)
341
8
{
342
    /* Set up structures needed to add the protocol subtree and manage it */
343
8
    proto_item *ti;
344
8
    proto_tree *S101_tree;
345
8
    tvbuff_t     *tvb_payload;
346
    /* Other misc. local variables. */
347
8
    int         offset = 0;
348
8
    int         parsedLen = 0;
349
8
    int         len    = 0;
350
8
    int         current_offset;
351
8
    int         datalen = 0;
352
8
    uint16_t crc_data;
353
8
    uint64_t msgLength = 0;
354
8
    uint16_t crc;
355
8
    uint8_t start, slot, message, version, dtd, command, flags = 0xFF, app_bytes[APP_BYTES_LEN];
356
357
    /* Check that the packet is long enough for it to belong to us. */
358
8
    len = tvb_reported_length(tvb);
359
8
    if (len < S101_MIN_LENGTH)
360
2
        return 0;
361
362
6
    current_offset = 0;
363
6
    do {
364
6
        offset = current_offset;
365
6
        crc = 0xFFFF;
366
6
        if (0 == find_s101_packet_header(tvb, &offset, &start, &slot, &message, &version, &dtd,  &command, &flags, &app_bytes[0], &msgLength, &crc)) {
367
6
            break;
368
6
        }
369
0
        if (0 == current_offset) {
370
            /* Set the Protocol column to the constant string of S101 */
371
0
            col_set_str(pinfo->cinfo, COL_PROTOCOL, "S101");
372
0
        }
373
374
        /* create display subtree for the protocol */
375
0
        ti = proto_tree_add_item(tree, proto_S101, tvb, current_offset, -1, ENC_NA);
376
377
0
        S101_tree = proto_item_add_subtree(ti, ett_S101);
378
0
        proto_tree_add_item(S101_tree, hf_S101_frame_format, tvb, current_offset++, 1, ENC_BIG_ENDIAN);
379
380
0
        if (msgLength != 0) {
381
            // Variant 2, the header contains a frame length
382
0
            int lengthSize = (int)(msgLength >> 56) & 0xF;
383
0
            proto_tree_add_item(S101_tree, hf_S101_length_size, tvb, current_offset++, 1, ENC_BIG_ENDIAN);
384
0
            proto_tree_add_item(S101_tree, hf_S101_message_length, tvb, current_offset,lengthSize, ENC_NA);
385
0
            current_offset += lengthSize;
386
0
        }
387
0
        proto_tree_add_item(S101_tree, hf_S101_slot, tvb, current_offset++, 1, ENC_BIG_ENDIAN);
388
0
        proto_tree_add_item(S101_tree, hf_S101_message_type, tvb, current_offset++,1, ENC_BIG_ENDIAN);
389
0
        proto_tree_add_item(S101_tree, hf_S101_cmd_type, tvb,current_offset++, 1, ENC_BIG_ENDIAN);
390
0
        proto_tree_add_item(S101_tree, hf_S101_version, tvb, current_offset++, 1, ENC_BIG_ENDIAN);
391
392
0
        if (command == S101_CMD_EMBER) {
393
0
            proto_tree_add_item(S101_tree, hf_S101_flags, tvb, current_offset++, 1, ENC_BIG_ENDIAN);
394
0
            proto_tree_add_item(S101_tree, hf_S101_dtd_type, tvb, current_offset++, 1, ENC_BIG_ENDIAN);
395
0
            proto_tree_add_item(S101_tree, hf_S101_app_bytes_len, tvb, current_offset++, 1, ENC_BIG_ENDIAN);
396
0
            proto_tree_add_item(S101_tree, hf_S101_dtd_minor_ver, tvb, current_offset++, 1, ENC_BIG_ENDIAN);
397
0
            proto_tree_add_item(S101_tree, hf_S101_dtd_major_ver, tvb, current_offset++, 1, ENC_BIG_ENDIAN);
398
0
        }
399
400
0
        if (msgLength == 0) {
401
            //Variant 1 - data is encoded with escaped bytes.
402
0
            tvb_payload = decode_s101_escaped_buffer(tvb, pinfo, &current_offset, &crc);
403
0
            datalen = tvb_captured_length(tvb_payload);
404
0
            crc_data = tvb_get_ntohs(tvb, current_offset - 3);
405
0
            proto_tree_add_checksum(S101_tree, tvb, current_offset - 3, hf_S101_crc, hf_S101_crc_status, NULL,
406
0
                                    pinfo, crc == S101_VALID_CRC ? crc_data : crc ^ crc_data, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY);
407
0
            proto_tree_add_item(S101_tree, hf_S101_eof, tvb, current_offset - 1, 1, ENC_BIG_ENDIAN);
408
0
        }
409
0
        else {
410
            //variant 2.  Packet size is provided and no encoding
411
0
            datalen = (int)(msgLength & 0x0FFFFFFF) - S101_HEADER_DATA_LENGTH;
412
0
            tvb_payload = tvb_new_subset_length(tvb, current_offset, datalen);
413
0
            current_offset += datalen;
414
0
        }
415
416
0
        proto_item_set_len(ti, current_offset - offset);
417
418
0
        if (command == S101_CMD_EMBER) {
419
0
            if (flags != FLAG_SINGLE_PACKET) {
420
0
                fragment_head *frag_msg = NULL;
421
0
                uint32_t id = get_fragment_pdu_id(pinfo);
422
0
                s101_fragment_t* fi = (s101_fragment_t*)wmem_map_lookup(s101_fragment_info_hash, &id);
423
0
                pinfo->fragmented = true;
424
425
0
                if (flags == FLAG_FIRST_MULTI_PACKET) {
426
0
                    if (NULL == fi) {
427
0
                        fi = new_fragment_info(pinfo);
428
0
                        wmem_map_insert(s101_fragment_info_hash, &id, fi);
429
0
                    }
430
0
                    else {
431
0
                        fi->id = pinfo->num;
432
0
                    }
433
0
                    fragment_add(&s101_data_reassembly_table, tvb_payload, 0,
434
0
                             pinfo, fi->id, NULL,
435
0
                             0, datalen,
436
0
                             true);
437
0
                    fi->offset = datalen;
438
0
                }
439
0
                else if (flags == FLAG_LAST_MULTI_PACKET) {
440
0
                    if (NULL != fi) {
441
                        // last fragment
442
0
                        frag_msg = fragment_add(&s101_data_reassembly_table, tvb_payload, 0,
443
0
                                            pinfo, fi->id, NULL,
444
0
                                            fi->offset, datalen,
445
0
                                            false);
446
0
                        tvb_payload = process_reassembled_data(tvb, offset, pinfo,
447
0
                                                           "Reassembled Message", frag_msg, &msg_frag_items,
448
0
                                                           NULL, S101_tree);
449
0
                    }
450
0
                    if (frag_msg) { /* Reassembled */
451
0
                        col_append_str(pinfo->cinfo, COL_INFO,
452
0
                               " (Message Reassembled)");
453
0
                    }
454
0
                    else {
455
0
                        display_expert_info(S101_tree, tvb, pinfo, offset, current_offset - offset);
456
0
                    }
457
0
                }
458
0
                else if (NULL == fi) {
459
0
                    display_expert_info(S101_tree, tvb, pinfo, offset, current_offset - offset);
460
0
                }
461
0
                else if (flags == FLAG_MULTI_PACKET) {
462
0
                    fragment_add(&s101_data_reassembly_table, tvb_payload, 0,
463
0
                             pinfo, fi->id, NULL,
464
0
                             fi->offset, datalen,
465
0
                             true);
466
0
                    fi->offset += datalen;
467
0
                    col_append_str(pinfo->cinfo, COL_INFO,
468
0
                                " (Message fragment)");
469
0
                }
470
0
            }
471
472
            // Call ASN1 Glow dissector - see epan/dissectors/asn1/glow/ if packet is complete.
473
0
            if ((flags == FLAG_LAST_MULTI_PACKET) && (tvb_payload == NULL)) {
474
0
                proto_item* pi;
475
0
                proto_tree_add_subtree(S101_tree, tvb, offset, current_offset - offset,
476
0
                                ett_decoding_error, &pi, "S101 Error");
477
0
                expert_add_info(pinfo, pi, &ei_s101_failed_reassembly);
478
0
            }
479
0
            else if ((glow_handle != NULL) && ((flags == FLAG_LAST_MULTI_PACKET) || (flags == FLAG_SINGLE_PACKET))) {
480
0
                parsedLen = call_dissector_only(glow_handle, tvb_payload, pinfo, S101_tree, data);
481
0
                if (parsedLen <= 0) {
482
0
                    break;
483
0
                }
484
0
            }
485
0
        }
486
0
    }while(current_offset < len);
487
6
    return current_offset;
488
8
}
489
490
/* Register the protocol with Wireshark.
491
 *
492
 * This format is required because a script is used to build the C function that
493
 * calls all the protocol registration.
494
 */
495
void
496
proto_register_S101(void)
497
16
{
498
16
    expert_module_t* expert_s101;
499
500
    /* Setup list of header fields  See Section 1.5 of README.dissector for
501
     * details. */
502
16
    static hf_register_info hf[] = {
503
16
        { &hf_S101_frame_format,
504
16
            { "Frame Format", "s101.format",
505
16
               FT_UINT8, BASE_HEX, VALS(frame_format_vs), 0x0, NULL, HFILL }},
506
507
16
        { &hf_S101_length_size,
508
16
            { "Bytes for Length", "s101.lensize",
509
16
              FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
510
511
16
        { &hf_S101_message_length,
512
16
            { "Message Length", "s101.msglen",
513
16
              FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
514
515
16
        { &hf_S101_slot,
516
16
            { "Slot", "s101.slot",
517
16
              FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
518
519
16
        { &hf_S101_message_type,
520
16
          { "Message Type", "s101.msgtype",
521
16
            FT_UINT8, BASE_HEX, VALS(message_type_vs), 0x0, NULL, HFILL }},
522
523
16
        { &hf_S101_cmd_type,
524
16
            { "Command Type", "s101.cmdtype",
525
16
              FT_UINT8, BASE_HEX, VALS(command_type_vs), 0x0, NULL, HFILL }},
526
527
16
        { &hf_S101_version,
528
16
            { "Version", "s101.version",
529
16
              FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
530
531
16
        { &hf_S101_flags,
532
16
            { "Flags", "s101.flags",
533
16
              FT_UINT8, BASE_HEX, VALS(flags_vs), 0x0, NULL, HFILL }},
534
535
16
        { &hf_S101_dtd_type,
536
16
            { "DTD Type", "s101.dtdtype",
537
16
              FT_UINT8, BASE_DEC, VALS(dtd_type_vs), 0x0, NULL, HFILL }},
538
539
16
        { &hf_S101_app_bytes_len,
540
16
            { "App Bytes Length", "s101.applen",
541
16
              FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
542
543
16
        { &hf_S101_dtd_minor_ver,
544
16
            { "App Minor Version", "s101.appminver",
545
16
               FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
546
547
16
        { &hf_S101_dtd_major_ver,
548
16
            { "App Major Version", "s101.appmajver",
549
16
              FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
550
551
16
        { &hf_S101_crc,
552
16
            { "CRC", "s101.crc",
553
16
              FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
554
555
16
        { &hf_S101_crc_status,
556
16
          { "Checksum Status", "s101.crc.status",
557
16
                FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0,
558
16
                NULL, HFILL }},
559
560
16
        { &hf_S101_eof,
561
16
            { "End of Frame", "s101.eof",
562
16
              FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
563
564
16
        { &hf_S101_error, {
565
16
                "S101 Error", "s101.error", FT_STRING, BASE_NONE,
566
16
                NULL, 0, NULL, HFILL }},
567
568
        // fragments info
569
16
        {&hf_msg_fragments,
570
16
            { "Message fragments", "s101.msg.fragments",
571
16
              FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL }},
572
573
16
        {&hf_msg_fragment,
574
16
            { "Message fragment", "s101.msg.fragment",
575
16
              FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL }},
576
577
16
        {&hf_msg_fragment_overlap,
578
16
            { "Message fragment overlap", "s101.msg.fragment.overlap",
579
16
              FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }},
580
581
16
        {&hf_msg_fragment_overlap_conflicts,
582
16
            { "Message fragment overlapping with conflicting data", "s101.msg.fragment.overlap.conflicts",
583
16
              FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }},
584
585
16
        {&hf_msg_fragment_multiple_tails,
586
16
            { "Message has multiple tail fragments", "s101.msg.fragment.multiple_tails",
587
16
              FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }},
588
589
16
        {&hf_msg_fragment_too_long_fragment,
590
16
            { "Message fragment too long", "s101.msg.fragment.too_long_fragment",
591
16
              FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }},
592
593
16
        {&hf_msg_fragment_error,
594
16
            { "Message defragmentation error", "s101.msg.fragment.error",
595
16
              FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL }},
596
597
16
        {&hf_msg_fragment_count,
598
16
            { "Message fragment count", "s101.msg.fragment.count",
599
16
              FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }},
600
601
16
        {&hf_msg_reassembled_in,
602
16
            { "Reassembled in", "s101.msg.reassembled.in",
603
16
              FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL }},
604
605
16
        {&hf_msg_reassembled_length,
606
16
            { "Reassembled length", "s101.msg.reassembled.length",
607
16
              FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }},
608
609
16
        {&hf_msg_reassembled_data,
610
16
            { "Reassembled Data", "s101.msg.reassembled.data",
611
16
              FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }},
612
16
    };
613
614
    /* Setup protocol subtree array */
615
16
    static int *ett[] = {
616
16
        &ett_S101,
617
16
        &ett_msg_fragment,
618
16
        &ett_msg_fragments,
619
16
        &ett_decoding_error
620
16
    };
621
622
16
    static ei_register_info ei[] = {
623
16
        { &ei_s101_failed_reassembly, { "s101.reassembly_error", PI_MALFORMED, PI_WARN, "Reassembly Error", EXPFILL }},
624
16
    };
625
626
    /* Register the protocol name and description */
627
16
    proto_S101 = proto_register_protocol("S101", "S101", "s101");
628
629
    /* Required function calls to register the header fields and subtrees */
630
16
    proto_register_field_array(proto_S101, hf, array_length(hf));
631
16
    proto_register_subtree_array(ett, array_length(ett));
632
633
16
    S101_handle = register_dissector("s101", dissect_S101, proto_S101);
634
635
16
    reassembly_table_register(&s101_data_reassembly_table,
636
16
                              &addresses_ports_reassembly_table_functions);
637
638
16
    s101_fragment_info_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
639
16
                                                     g_direct_hash, g_direct_equal);
640
641
    /* S101_module = prefs_register_protocol(proto_S101, NULL); */
642
643
16
    expert_s101 = expert_register_protocol(proto_S101);
644
16
    expert_register_field_array(expert_s101, ei, array_length(ei));
645
16
}
646
647
void
648
proto_reg_handoff_S101(void)
649
16
{
650
16
    glow_handle = find_dissector_add_dependency("glow", proto_S101);
651
16
    dissector_add_uint_with_preference("tcp.port", S101_TCP_PORT, S101_handle);
652
16
}
653
654
/*
655
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
656
 *
657
 * Local variables:
658
 * c-basic-offset: 4
659
 * tab-width: 8
660
 * indent-tabs-mode: nil
661
 * End:
662
 *
663
 * vi: set shiftwidth=4 tabstop=8 expandtab:
664
 * :indentSize=4:tabSize=8:noTabs=true:
665
 */