2 * Routines for S101 dissection
3 * Copyright 2018, Gilles Dufour <dufour.gilles@gmail.com>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
13 * This Dissector will dissect S101 frames used by Lawo Ember Plus protocol.
14 * https://github.com/Lawo/ember-plus/
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>
26 #define S101_HEADER_DATA_LENGTH 9
32 #define S101_SLOT 0x00
33 #define S101_MSG_EMBER 0x0E
34 #define S101_CMD_EMBER 0x00
35 #define S101_CMD_KEEPALIVE_REQ 0x01
36 #define S101_CMD_KEEPALIVE_RESP 0x02
37 #define S101_VERSION 0x01
38 #define FLAG_SINGLE_PACKET 0xC0
39 #define FLAG_FIRST_MULTI_PACKET 0x80
40 #define FLAG_LAST_MULTI_PACKET 0x40
41 #define FLAG_EMPTY_PACKET 0x20
42 #define FLAG_MULTI_PACKET 0x00
43 #define S101_DTD_GLOW 0x01
44 #define S101_DTD_VERSION_MAJOR 0x02
45 #define S101_DTD_VERSION_MINOR 0x1F
46 #define S101_VALID_CRC 0xF0B8
47 #define APP_BYTES_LEN 2
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
;
66 static dissector_handle_t S101_handle
;
67 static dissector_handle_t glow_handle
;
68 static reassembly_table s101_data_reassembly_table
;
70 typedef struct _s101_fragment_t
{
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
);
84 /* Initialize the protocol and registered fields */
85 static int proto_S101
;
87 /* Real port preferences should generally default to 0 unless there is an
88 * IANA-registered (or equivalent) port for your protocol. */
89 #define S101_TCP_PORT 9000 /* Not IANA-registered */
91 /* Initialize the subtree pointers */
93 static int ett_decoding_error
;
95 #define S101_MIN_LENGTH 5
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
;
110 static expert_field ei_s101_failed_reassembly
;
112 static int ett_msg_fragment
;
113 static int ett_msg_fragments
;
115 static const fragment_items msg_frag_items
= {
116 /* Fragment subtrees */
119 /* Fragment fields */
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
,
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.
143 static uint32_t get_fragment_pdu_id(packet_info
*pinfo
) {
144 uint32_t id
= pinfo
->srcport
<< 16;
145 const uint8_t *data
= (const uint8_t*)pinfo
->src
.data
;
146 if (pinfo
->src
.len
>= 2) {
147 id
= id
+ (((uint32_t)data
[pinfo
->src
.len
- 2]) << 8) + (uint32_t)data
[pinfo
->src
.len
- 1];
152 static wmem_map_t
* s101_fragment_info_hash
;
154 static s101_fragment_t
* new_fragment_info(packet_info
*pinfo
) {
155 s101_fragment_t
* fi
= wmem_new(wmem_file_scope(), s101_fragment_t
);
156 if (NULL
== fi
) { return fi
; }
163 If byte escaped, get the unescaped value
165 static uint8_t get_byte(tvbuff_t
*tvb
, int *offset
, uint16_t *crc
) {
166 uint8_t b
= tvb_get_uint8(tvb
, *offset
);
167 *crc
= crc16_ccitt_seed(&b
, 1, *crc
) ^ 0xFFFF;
168 *offset
= *offset
+ 1;
170 b
= tvb_get_uint8(tvb
, *offset
);
171 *crc
= crc16_ccitt_seed(&b
, 1, *crc
) ^ 0xFFFF;
172 *offset
= *offset
+ 1;
173 return (b
^ S101_XOR
);
180 static const value_string frame_format_vs
[] = {
181 { S101_BOF
, "Escaped Frame" },
182 { S101_INV
, "UnEscaped Frame"},
186 static const value_string message_type_vs
[] = {
187 { S101_MSG_EMBER
, "Ember" },
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" },
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" },
207 static const value_string dtd_type_vs
[] = {
208 { S101_DTD_GLOW
, "DTD Glow" },
215 display_expert_info(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo
, int offset
, int len
) {
217 proto_tree
*error_tree
;
219 error_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, len
,
220 ett_decoding_error
, &pi
, "S101 Error");
222 pi
= proto_tree_add_string_format_value(
223 error_tree
, hf_S101_error
, tvb
, offset
, len
, "s101_error",
226 expert_add_info(pinfo
, pi
, &ei_s101_failed_reassembly
);
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.
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
)
240 uint8_t app_bytes_len
= 0;
243 *start
= tvb_get_uint8(tvb
, *offset
); // no CRC and no escaping on first bytes.
244 *offset
= *offset
+ 1;
245 if (*start
== S101_INV
) { // Variant 2 of header - unescaped data
246 //Read the frame length
247 app_bytes_len
= tvb_get_uint8(tvb
, *offset
) & 0x7;
248 *offset
= *offset
+ 1;
250 if (app_bytes_len
> 1) {
251 *msgLength
= tvb_get_bits64 (tvb
, *offset
, app_bytes_len
* 8, ENC_BIG_ENDIAN
);
252 *msgLength
= *msgLength
+ (((uint64_t)app_bytes_len
) << 56);
253 *offset
= app_bytes_len
;
256 else if (*start
!= S101_BOF
) {
257 // IF NOT Beginning of Frame - variant 1 - escaped data
264 *slot
= get_byte(tvb
, offset
, crc
);
265 *message
= get_byte(tvb
, offset
, crc
);
266 *command
= get_byte(tvb
, offset
, crc
);
267 *version
= get_byte(tvb
, offset
, crc
);
269 if (*command
== S101_CMD_EMBER
) {
270 *flags
= get_byte(tvb
, offset
, crc
);
271 *dtd
= get_byte(tvb
, offset
, crc
);
272 app_bytes_len
= get_byte(tvb
, offset
, crc
);
274 if ((S101_SLOT
!= *slot
) ||
275 (S101_MSG_EMBER
!= *message
) || (*command
> S101_CMD_KEEPALIVE_RESP
) ||
276 (S101_VERSION
!= *version
) ||
277 ((*command
== S101_CMD_EMBER
) &&
278 ((*flags
& 0xF) || (S101_DTD_GLOW
!= *dtd
) || (APP_BYTES_LEN
!= app_bytes_len
)))) {
281 if (*command
== S101_CMD_EMBER
) {
282 for(i
= 0; i
< APP_BYTES_LEN
; i
++) {
283 app_bytes
[i
] = get_byte(tvb
, offset
, crc
);
290 decode_s101_escaped_buffer(tvbuff_t
*tvb
, packet_info
*pinfo
, int *offset
, uint16_t *crc
) {
294 unsigned char *decoded_buffer
;
297 len
= tvb_captured_length(tvb
);
301 decoded_buffer
= (unsigned char*)wmem_alloc(pinfo
->pool
, len
);
302 if (decoded_buffer
== NULL
) {
306 for(i
= 0; *offset
< len
; ) {
307 b
= tvb_get_uint8(tvb
, *offset
);
308 *offset
= *offset
+ 1;
311 b
= tvb_get_uint8(tvb
, *offset
);
312 *offset
= *offset
+ 1;
314 decoded_buffer
[i
++] = b
;
317 decoded_buffer
[i
] = b
;
318 if (b
== S101_EOF
) { // End of Frame
319 // let's remove the CRC and the EOF
327 *crc
= crc16_ccitt_seed(&b
, 1, *crc
) ^ 0xFFFF;
330 next_tvb
= tvb_new_child_real_data(tvb
, decoded_buffer
, i
, i
);
331 add_new_data_source(pinfo
, next_tvb
, "Decoded Data");
337 /* Code to actually dissect the packets */
339 dissect_S101(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
342 /* Set up structures needed to add the protocol subtree and manage it */
344 proto_tree
*S101_tree
;
345 tvbuff_t
*tvb_payload
;
346 /* Other misc. local variables. */
353 uint64_t msgLength
= 0;
355 uint8_t start
, slot
, message
, version
, dtd
, command
, flags
= 0xFF, app_bytes
[APP_BYTES_LEN
];
357 /* Check that the packet is long enough for it to belong to us. */
358 len
= tvb_reported_length(tvb
);
359 if (len
< S101_MIN_LENGTH
)
364 offset
= current_offset
;
366 if (0 == find_s101_packet_header(tvb
, &offset
, &start
, &slot
, &message
, &version
, &dtd
, &command
, &flags
, &app_bytes
[0], &msgLength
, &crc
)) {
369 if (0 == current_offset
) {
370 /* Set the Protocol column to the constant string of S101 */
371 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "S101");
374 /* create display subtree for the protocol */
375 ti
= proto_tree_add_item(tree
, proto_S101
, tvb
, current_offset
, -1, ENC_NA
);
377 S101_tree
= proto_item_add_subtree(ti
, ett_S101
);
378 proto_tree_add_item(S101_tree
, hf_S101_frame_format
, tvb
, current_offset
++, 1, ENC_BIG_ENDIAN
);
380 if (msgLength
!= 0) {
381 // Variant 2, the header contains a frame length
382 int lengthSize
= (int)(msgLength
>> 56) & 0xF;
383 proto_tree_add_item(S101_tree
, hf_S101_length_size
, tvb
, current_offset
++, 1, ENC_BIG_ENDIAN
);
384 proto_tree_add_item(S101_tree
, hf_S101_message_length
, tvb
, current_offset
,lengthSize
, ENC_NA
);
385 current_offset
+= lengthSize
;
387 proto_tree_add_item(S101_tree
, hf_S101_slot
, tvb
, current_offset
++, 1, ENC_BIG_ENDIAN
);
388 proto_tree_add_item(S101_tree
, hf_S101_message_type
, tvb
, current_offset
++,1, ENC_BIG_ENDIAN
);
389 proto_tree_add_item(S101_tree
, hf_S101_cmd_type
, tvb
,current_offset
++, 1, ENC_BIG_ENDIAN
);
390 proto_tree_add_item(S101_tree
, hf_S101_version
, tvb
, current_offset
++, 1, ENC_BIG_ENDIAN
);
392 if (command
== S101_CMD_EMBER
) {
393 proto_tree_add_item(S101_tree
, hf_S101_flags
, tvb
, current_offset
++, 1, ENC_BIG_ENDIAN
);
394 proto_tree_add_item(S101_tree
, hf_S101_dtd_type
, tvb
, current_offset
++, 1, ENC_BIG_ENDIAN
);
395 proto_tree_add_item(S101_tree
, hf_S101_app_bytes_len
, tvb
, current_offset
++, 1, ENC_BIG_ENDIAN
);
396 proto_tree_add_item(S101_tree
, hf_S101_dtd_minor_ver
, tvb
, current_offset
++, 1, ENC_BIG_ENDIAN
);
397 proto_tree_add_item(S101_tree
, hf_S101_dtd_major_ver
, tvb
, current_offset
++, 1, ENC_BIG_ENDIAN
);
400 if (msgLength
== 0) {
401 //Variant 1 - data is encoded with escaped bytes.
402 tvb_payload
= decode_s101_escaped_buffer(tvb
, pinfo
, ¤t_offset
, &crc
);
403 datalen
= tvb_captured_length(tvb_payload
);
404 crc_data
= tvb_get_ntohs(tvb
, current_offset
- 3);
405 proto_tree_add_checksum(S101_tree
, tvb
, current_offset
- 3, hf_S101_crc
, hf_S101_crc_status
, NULL
,
406 pinfo
, crc
== S101_VALID_CRC
? crc_data
: crc
^ crc_data
, ENC_BIG_ENDIAN
, PROTO_CHECKSUM_VERIFY
);
407 proto_tree_add_item(S101_tree
, hf_S101_eof
, tvb
, current_offset
- 1, 1, ENC_BIG_ENDIAN
);
410 //variant 2. Packet size is provided and no encoding
411 datalen
= (int)(msgLength
& 0x0FFFFFFF) - S101_HEADER_DATA_LENGTH
;
412 tvb_payload
= tvb_new_subset_length(tvb
, current_offset
, datalen
);
413 current_offset
+= datalen
;
416 proto_item_set_len(ti
, current_offset
- offset
);
418 if (command
== S101_CMD_EMBER
) {
419 if (flags
!= FLAG_SINGLE_PACKET
) {
420 fragment_head
*frag_msg
= NULL
;
421 uint32_t id
= get_fragment_pdu_id(pinfo
);
422 s101_fragment_t
* fi
= (s101_fragment_t
*)wmem_map_lookup(s101_fragment_info_hash
, &id
);
423 pinfo
->fragmented
= true;
425 if (flags
== FLAG_FIRST_MULTI_PACKET
) {
427 fi
= new_fragment_info(pinfo
);
428 wmem_map_insert(s101_fragment_info_hash
, &id
, fi
);
433 fragment_add(&s101_data_reassembly_table
, tvb_payload
, 0,
437 fi
->offset
= datalen
;
439 else if (flags
== FLAG_LAST_MULTI_PACKET
) {
442 frag_msg
= fragment_add(&s101_data_reassembly_table
, tvb_payload
, 0,
446 tvb_payload
= process_reassembled_data(tvb
, offset
, pinfo
,
447 "Reassembled Message", frag_msg
, &msg_frag_items
,
450 if (frag_msg
) { /* Reassembled */
451 col_append_str(pinfo
->cinfo
, COL_INFO
,
452 " (Message Reassembled)");
455 display_expert_info(S101_tree
, tvb
, pinfo
, offset
, current_offset
- offset
);
458 else if (NULL
== fi
) {
459 display_expert_info(S101_tree
, tvb
, pinfo
, offset
, current_offset
- offset
);
461 else if (flags
== FLAG_MULTI_PACKET
) {
462 fragment_add(&s101_data_reassembly_table
, tvb_payload
, 0,
466 fi
->offset
+= datalen
;
467 col_append_str(pinfo
->cinfo
, COL_INFO
,
468 " (Message fragment)");
472 // Call ASN1 Glow dissector - see epan/dissectors/asn1/glow/ if packet is complete.
473 if ((flags
== FLAG_LAST_MULTI_PACKET
) && (tvb_payload
== NULL
)) {
475 proto_tree_add_subtree(S101_tree
, tvb
, offset
, current_offset
- offset
,
476 ett_decoding_error
, &pi
, "S101 Error");
477 expert_add_info(pinfo
, pi
, &ei_s101_failed_reassembly
);
479 else if ((glow_handle
!= NULL
) && ((flags
== FLAG_LAST_MULTI_PACKET
) || (flags
== FLAG_SINGLE_PACKET
))) {
480 parsedLen
= call_dissector_only(glow_handle
, tvb_payload
, pinfo
, S101_tree
, data
);
481 if (parsedLen
<= 0) {
486 }while(current_offset
< len
);
487 return current_offset
;
490 /* Register the protocol with Wireshark.
492 * This format is required because a script is used to build the C function that
493 * calls all the protocol registration.
496 proto_register_S101(void)
498 expert_module_t
* expert_s101
;
500 /* Setup list of header fields See Section 1.5 of README.dissector for
502 static hf_register_info hf
[] = {
503 { &hf_S101_frame_format
,
504 { "Frame Format", "s101.format",
505 FT_UINT8
, BASE_HEX
, VALS(frame_format_vs
), 0x0, NULL
, HFILL
}},
507 { &hf_S101_length_size
,
508 { "Bytes for Length", "s101.lensize",
509 FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
511 { &hf_S101_message_length
,
512 { "Message Length", "s101.msglen",
513 FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
516 { "Slot", "s101.slot",
517 FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
519 { &hf_S101_message_type
,
520 { "Message Type", "s101.msgtype",
521 FT_UINT8
, BASE_HEX
, VALS(message_type_vs
), 0x0, NULL
, HFILL
}},
524 { "Command Type", "s101.cmdtype",
525 FT_UINT8
, BASE_HEX
, VALS(command_type_vs
), 0x0, NULL
, HFILL
}},
528 { "Version", "s101.version",
529 FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
532 { "Flags", "s101.flags",
533 FT_UINT8
, BASE_HEX
, VALS(flags_vs
), 0x0, NULL
, HFILL
}},
536 { "DTD Type", "s101.dtdtype",
537 FT_UINT8
, BASE_DEC
, VALS(dtd_type_vs
), 0x0, NULL
, HFILL
}},
539 { &hf_S101_app_bytes_len
,
540 { "App Bytes Length", "s101.applen",
541 FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
543 { &hf_S101_dtd_minor_ver
,
544 { "App Minor Version", "s101.appminver",
545 FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
547 { &hf_S101_dtd_major_ver
,
548 { "App Major Version", "s101.appmajver",
549 FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
553 FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
555 { &hf_S101_crc_status
,
556 { "Checksum Status", "s101.crc.status",
557 FT_UINT8
, BASE_NONE
, VALS(proto_checksum_vals
), 0x0,
561 { "End of Frame", "s101.eof",
562 FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
565 "S101 Error", "s101.error", FT_STRING
, BASE_NONE
,
566 NULL
, 0, NULL
, HFILL
}},
570 { "Message fragments", "s101.msg.fragments",
571 FT_NONE
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}},
574 { "Message fragment", "s101.msg.fragment",
575 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}},
577 {&hf_msg_fragment_overlap
,
578 { "Message fragment overlap", "s101.msg.fragment.overlap",
579 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}},
581 {&hf_msg_fragment_overlap_conflicts
,
582 { "Message fragment overlapping with conflicting data", "s101.msg.fragment.overlap.conflicts",
583 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}},
585 {&hf_msg_fragment_multiple_tails
,
586 { "Message has multiple tail fragments", "s101.msg.fragment.multiple_tails",
587 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}},
589 {&hf_msg_fragment_too_long_fragment
,
590 { "Message fragment too long", "s101.msg.fragment.too_long_fragment",
591 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}},
593 {&hf_msg_fragment_error
,
594 { "Message defragmentation error", "s101.msg.fragment.error",
595 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}},
597 {&hf_msg_fragment_count
,
598 { "Message fragment count", "s101.msg.fragment.count",
599 FT_UINT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
}},
601 {&hf_msg_reassembled_in
,
602 { "Reassembled in", "s101.msg.reassembled.in",
603 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}},
605 {&hf_msg_reassembled_length
,
606 { "Reassembled length", "s101.msg.reassembled.length",
607 FT_UINT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
}},
609 {&hf_msg_reassembled_data
,
610 { "Reassembled Data", "s101.msg.reassembled.data",
611 FT_BYTES
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}},
614 /* Setup protocol subtree array */
615 static int *ett
[] = {
622 static ei_register_info ei
[] = {
623 { &ei_s101_failed_reassembly
, { "s101.reassembly_error", PI_MALFORMED
, PI_WARN
, "Reassembly Error", EXPFILL
}},
626 /* Register the protocol name and description */
627 proto_S101
= proto_register_protocol("S101", "S101", "s101");
629 /* Required function calls to register the header fields and subtrees */
630 proto_register_field_array(proto_S101
, hf
, array_length(hf
));
631 proto_register_subtree_array(ett
, array_length(ett
));
633 S101_handle
= register_dissector("s101", dissect_S101
, proto_S101
);
635 reassembly_table_register(&s101_data_reassembly_table
,
636 &addresses_ports_reassembly_table_functions
);
638 s101_fragment_info_hash
= wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
639 g_direct_hash
, g_direct_equal
);
641 /* S101_module = prefs_register_protocol(proto_S101, NULL); */
643 expert_s101
= expert_register_protocol(proto_S101
);
644 expert_register_field_array(expert_s101
, ei
, array_length(ei
));
648 proto_reg_handoff_S101(void)
650 glow_handle
= find_dissector_add_dependency("glow", proto_S101
);
651 dissector_add_uint_with_preference("tcp.port", S101_TCP_PORT
, S101_handle
);
655 * Editor modelines - https://www.wireshark.org/tools/modelines.html
660 * indent-tabs-mode: nil
663 * vi: set shiftwidth=4 tabstop=8 expandtab:
664 * :indentSize=4:tabSize=8:noTabs=true: