3 * Copyright (c) 2010, Holger Grandy, BMW Car IT GmbH (holger.grandy@bmw-carit.de)
5 * Apache Etch Protocol dissector
6 * http://incubator.apache.org/etch/
8 * This dissector reads configuration files (generated by Etch IDL compiler).
9 * Configuration file directory path is given in dissector options.
11 * Wireshark - Network traffic analyzer
12 * By Gerald Combs <gerald@wireshark.org>
13 * Copyright 1998 Gerald Combs
16 * SPDX-License-Identifier: GPL-2.0-or-later
21 #include <epan/packet.h>
22 #include <epan/prefs.h>
23 #include <wsutil/file_util.h>
24 #include <wsutil/report_message.h>
25 #include "packet-tcp.h"
27 void proto_register_etch(void);
28 void proto_reg_handoff_etch(void);
31 * maximum numbers for symbols from config files
33 #define ETCH_MAX_SYMBOL_LENGTH "256"
36 * Magic Number for Etch
38 static const uint8_t etch_magic
[] = { 0xde, 0xad, 0xbe, 0xef };
41 * Typecodes in the Etch protocol, representing the field types
43 #define ETCH_TC_NULL 0x80
44 #define ETCH_TC_NONE 0x81
45 #define ETCH_TC_BOOLEAN_FALSE 0x82
46 #define ETCH_TC_BOOLEAN_TRUE 0x83
47 #define ETCH_TC_BYTE 0x84
48 #define ETCH_TC_SHORT 0x85
49 #define ETCH_TC_INT 0x86
50 #define ETCH_TC_LONG 0x87
51 #define ETCH_TC_FLOAT 0x88
52 #define ETCH_TC_DOUBLE 0x89
53 #define ETCH_TC_BYTES 0x8B
54 #define ETCH_TC_ARRAY 0x91
55 #define ETCH_TC_EMPTY_STRING 0x92
56 #define ETCH_TC_STRING 0x93
57 #define ETCH_TC_STRUCT 0x94
58 #define ETCH_TC_CUSTOM 0x95
59 #define ETCH_TC_ANY 0x96
60 #define ETCH_TC_MIN_TINY_INT 0xC0
61 #define ETCH_TC_MAX_TINY_INT 0x7F
63 /***************************************************************************/
67 * String representation of all Type Codes
69 static const value_string tc_lookup_table
[] = {
70 { ETCH_TC_NULL
, "Etch TypeCode: NULL"},
71 { ETCH_TC_NONE
, "Etch TypeCode: NONE"},
72 { ETCH_TC_BOOLEAN_FALSE
, "Etch TypeCode: BOOLEAN_FALSE" },
73 { ETCH_TC_BOOLEAN_TRUE
, "Etch TypeCode: BOOLEAN_TRUE"},
74 { ETCH_TC_BYTE
, "Etch TypeCode: BYTE"},
75 { ETCH_TC_SHORT
, "Etch TypeCode: SHORT"},
76 { ETCH_TC_INT
, "Etch TypeCode: INT"},
77 { ETCH_TC_LONG
, "Etch TypeCode: LONG"},
78 { ETCH_TC_FLOAT
, "Etch TypeCode: FLOAT"},
79 { ETCH_TC_DOUBLE
, "Etch TypeCode: DOUBLE"},
80 { ETCH_TC_BYTES
, "Etch TypeCode: BYTES"},
81 { ETCH_TC_ARRAY
, "Etch TypeCode: ARRAY"},
82 { ETCH_TC_EMPTY_STRING
, "Etch TypeCode: EMPTY_STRING"},
83 { ETCH_TC_STRING
, "Etch TypeCode: STRING"},
84 { ETCH_TC_STRUCT
, "Etch TypeCode: STRUCT"},
85 { ETCH_TC_CUSTOM
, "Etch TypeCode: CUSTOM"},
86 { ETCH_TC_ANY
, "Etch TypeCode: ANY"},
91 * Wireshark internal fields
93 static int proto_etch
;
95 static int ett_etch_struct
;
96 static int ett_etch_keyvalue
;
97 static int ett_etch_key
;
98 static int ett_etch_value
;
99 static int hf_etch_sig
;
100 static int hf_etch_length
;
101 static int hf_etch_version
;
102 static int hf_etch_typecode
;
103 static int hf_etch_value
;
104 static int hf_etch_bytes
;
105 static int hf_etch_byte
;
106 static int hf_etch_short
;
107 static int hf_etch_int
;
108 static int hf_etch_long
;
109 static int hf_etch_float
;
110 static int hf_etch_double
;
111 /* static int hf_etch_key; */
112 static int hf_etch_valuename
;
113 static int hf_etch_keyname
;
114 static int hf_etch_string
;
115 static int hf_etch_keyvalue
;
116 static int hf_etch_struct
;
117 static int hf_etch_dim
;
118 static int hf_etch_symbol
;
120 static dissector_handle_t etch_handle
;
123 * internal fields/defines for dissector
126 static const char *gbl_keytab_folder
= "";
127 static char *gbl_current_keytab_folder
;
129 static int gbl_pdu_counter
;
130 static uint32_t gbl_old_frame_num
;
132 static wmem_strbuf_t
*gbl_symbol_buffer
;
133 static bool gbl_have_symbol
;
135 /***************************************************************************/
139 * forward declared dissector methods
141 static void read_key_value(unsigned int *offset
, tvbuff_t
*tvb
,
142 proto_tree
*etch_tree
, packet_info
*pinfo
);
143 static void read_struct(unsigned int *offset
, tvbuff_t
*tvb
,
144 proto_tree
*etch_tree
, packet_info
*pinfo
, int add_type_field
);
145 static int read_value(unsigned int *offset
, tvbuff_t
*tvb
, proto_tree
*etch_tree
,
146 packet_info
*pinfo
, int asWhat
);
148 /************************************************************************
149 * Symbol value-string functions
150 * Essentially: Build a value_string_ext at runtime:
151 * a. Upon startup & whenever symbol folder changed: Read from file(s)
152 * and add all hash/symbol pairs to a GArray;
153 * b. When file reads complete, sort the GArray and then create a
154 * value_string_ext from the array for use by try_val_to_str_ext & friends.
155 * (Code based upon code in packet-diameter.c)
157 static GArray
*gbl_symbols_array
;
158 static value_string_ext
*gbl_symbols_vs_ext
;
161 gbl_symbols_new(void)
163 DISSECTOR_ASSERT(gbl_symbols_array
== NULL
);
164 gbl_symbols_array
= g_array_new(true, true, sizeof(value_string
));
168 gbl_symbols_free(void)
170 value_string_ext_free(gbl_symbols_vs_ext
);
171 gbl_symbols_vs_ext
= NULL
;
173 if (gbl_symbols_array
!= NULL
) {
176 vs_p
= (value_string
*)(void *)gbl_symbols_array
->data
;
177 for (i
=0; i
<gbl_symbols_array
->len
; i
++) {
178 g_free((char *)vs_p
[i
].strptr
);
180 g_array_free(gbl_symbols_array
, true);
181 gbl_symbols_array
= NULL
;
186 gbl_symbols_array_append(uint32_t hash
, char *symbol
)
188 value_string vs
= {hash
, symbol
};
189 DISSECTOR_ASSERT(gbl_symbols_array
!= NULL
);
190 g_array_append_val(gbl_symbols_array
, vs
);
194 gbl_symbols_compare_vs(const void * a
, const void * b
)
196 const value_string
*vsa
= (const value_string
*)a
;
197 const value_string
*vsb
= (const value_string
*)b
;
199 if(vsa
->value
> vsb
->value
)
201 if(vsa
->value
< vsb
->value
)
208 gbl_symbols_vs_ext_new(void)
210 DISSECTOR_ASSERT(gbl_symbols_vs_ext
== NULL
);
211 DISSECTOR_ASSERT(gbl_symbols_array
!= NULL
);
212 g_array_sort(gbl_symbols_array
, gbl_symbols_compare_vs
);
213 gbl_symbols_vs_ext
= value_string_ext_new((value_string
*)(void *)gbl_symbols_array
->data
,
214 gbl_symbols_array
->len
+1,
215 "etch-global-symbols" );
218 /*********************************************************************************/
222 * get the length of a given typecode in bytes, -1 if to be derived from message
225 get_byte_length(uint8_t typecode
)
230 case ETCH_TC_BOOLEAN_FALSE
:
231 case ETCH_TC_BOOLEAN_TRUE
:
232 case ETCH_TC_EMPTY_STRING
:
233 case ETCH_TC_MIN_TINY_INT
:
234 case ETCH_TC_MAX_TINY_INT
:
259 * add all etch symbols from file to our symbol cache
262 add_symbols_of_file(const char *filename
)
266 pFile
= ws_fopen(filename
, "r");
270 while (fgets(line
, sizeof line
, pFile
) != NULL
) {
274 length
= strlen(line
);
276 /* Must at least have a hash, else skip line */
281 while (pos
> 0 && (line
[pos
] == 0xD || line
[pos
] == 0xA)) {
284 line
[pos
+ 1] = '\0';
287 if (sscanf(&line
[0], "%x", &hash
) != 1)
288 continue; /* didn't find a valid hex value at the beginning of the line */
290 /* And read the symbol */
291 pos
= strcspn(line
, ",");
292 if ((line
[pos
] != '\0') && (line
[pos
+1] !='\0')) /* require at least 1 char in symbol */
293 gbl_symbols_array_append(hash
,
294 ws_strdup_printf("%." ETCH_MAX_SYMBOL_LENGTH
"s", &line
[pos
+1]));
301 * add all etch symbol from directory to our symbol cache
304 read_hashed_symbols_from_dir(const char *dirname
)
310 GError
*err_p
= NULL
;
312 if(gbl_current_keytab_folder
!= NULL
) {
313 g_free(gbl_current_keytab_folder
);
314 gbl_current_keytab_folder
= NULL
;
319 if ((dirname
== NULL
) || (dirname
[0] == '\0'))
322 if ((dir
= ws_dir_open(dirname
, 0, &err_p
)) != NULL
) {
325 gbl_current_keytab_folder
= g_strdup(dirname
);
326 while ((file
= ws_dir_read_name(dir
)) != NULL
) {
327 name
= ws_dir_get_name(file
);
329 if (g_str_has_suffix(file
, ".ewh")) {
331 ws_strdup_printf("%s" G_DIR_SEPARATOR_S
"%s", dirname
,
333 add_symbols_of_file(filename
);
338 gbl_symbols_vs_ext_new();
340 report_failure("etch: %s", err_p
->message
);
345 /***********************************************************************************/
346 /* Etch Protocol Functions */
349 * read a type flag from tvb and add it to tree
352 read_type(unsigned int *offset
, tvbuff_t
*tvb
, proto_tree
*etch_tree
)
357 type_code
= tvb_get_uint8(tvb
, *offset
);
358 proto_tree_add_item(etch_tree
, hf_etch_typecode
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
364 * read a array type flag and add it to tree
367 read_array_type(unsigned int *offset
, tvbuff_t
*tvb
, proto_tree
*etch_tree
)
371 type_code
= tvb_get_uint8(tvb
, *offset
);
373 read_type(offset
, tvb
, etch_tree
);
374 if (type_code
== ETCH_TC_CUSTOM
) {
375 read_type(offset
, tvb
, etch_tree
);
376 proto_tree_add_item(etch_tree
, hf_etch_value
, tvb
, *offset
, 4,
384 * read the length of an array and add it to tree
387 read_length(unsigned int *offset
, tvbuff_t
*tvb
, proto_tree
*etch_tree
)
390 int length_of_array_length_type
;
393 tiny
= tvb_get_uint8(tvb
, *offset
);
395 /* Is this the value already? */
396 if ( tiny
<= ETCH_TC_MAX_TINY_INT
397 || tiny
>= ETCH_TC_MIN_TINY_INT
) {
399 length_of_array_length_type
= 1;
402 type_code
= read_type(offset
, tvb
, etch_tree
);
403 length_of_array_length_type
= get_byte_length(type_code
);
405 switch (length_of_array_length_type
) {
407 length
= tvb_get_uint8(tvb
, *offset
);
410 length
= tvb_get_ntohs(tvb
, *offset
);
413 length
= tvb_get_ntohl(tvb
, *offset
);
416 return 0; /* error! */
419 proto_tree_add_item(etch_tree
, hf_etch_length
, tvb
, *offset
,
420 length_of_array_length_type
, ENC_BIG_ENDIAN
);
421 (*offset
) += length_of_array_length_type
;
423 if (*offset
+ length
< *offset
) {
425 * https://gitlab.com/wireshark/wireshark/-/issues/8464 */
426 length
= tvb_reported_length_remaining(tvb
, *offset
);
433 * read an array from tvb and add it to tree
436 // NOLINTNEXTLINE(misc-no-recursion)
437 read_array(unsigned int *offset
, tvbuff_t
*tvb
, proto_tree
*etch_tree
, packet_info
*pinfo
)
442 read_type(offset
, tvb
, etch_tree
);
445 read_array_type(offset
, tvb
, etch_tree
);
448 proto_tree_add_item(etch_tree
, hf_etch_dim
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
452 length
= read_length(offset
, tvb
, etch_tree
);
454 for (; length
> 0; length
--) {
455 read_value(offset
, tvb
, etch_tree
, pinfo
, hf_etch_value
);
458 read_type(offset
, tvb
, etch_tree
);
463 * read a sequence of bytes and add them to tree
466 read_bytes(unsigned int *offset
, tvbuff_t
*tvb
, proto_tree
*etch_tree
)
470 read_type(offset
, tvb
, etch_tree
);
471 length
= read_length(offset
, tvb
, etch_tree
);
472 proto_tree_add_item(etch_tree
, hf_etch_bytes
, tvb
, *offset
, length
,
478 * read a string and add it to tree
481 read_string(unsigned int *offset
, tvbuff_t
*tvb
, proto_tree
*etch_tree
)
485 read_type(offset
, tvb
, etch_tree
);
487 byteLength
= read_length(offset
, tvb
, etch_tree
);
489 proto_tree_add_item(etch_tree
, hf_etch_string
, tvb
, *offset
,
490 byteLength
, ENC_ASCII
);
491 (*offset
) += byteLength
;
495 * read a number and add it to tree
498 read_number(unsigned int *offset
, tvbuff_t
*tvb
, proto_tree
*etch_tree
,
499 int asWhat
, uint8_t type_code
)
503 read_type(offset
, tvb
, etch_tree
);
504 byteLength
= get_byte_length(type_code
);
505 if (byteLength
> 0) {
507 const char *symbol
= NULL
;
510 gbl_symbol_buffer
= wmem_strbuf_create(wmem_packet_scope()); /* no symbol found yet */
511 if (byteLength
== 4) {
512 hash
= tvb_get_ntohl(tvb
, *offset
);
513 symbol
= try_val_to_str_ext(hash
, gbl_symbols_vs_ext
);
515 asWhat
= hf_etch_symbol
;
516 gbl_have_symbol
= true;
517 wmem_strbuf_append_printf(gbl_symbol_buffer
,"%s",symbol
);
520 ti
= proto_tree_add_item(etch_tree
, asWhat
, tvb
, *offset
,
521 byteLength
, ENC_BIG_ENDIAN
);
522 *offset
+= byteLength
;
523 if (symbol
!= NULL
) {
524 proto_item_append_text(ti
, " (0x%08x) %s", hash
, symbol
);
530 * read a value and add it to tree
533 // NOLINTNEXTLINE(misc-no-recursion)
534 read_value(unsigned int *offset
, tvbuff_t
*tvb
, proto_tree
*etch_tree
,
535 packet_info
*pinfo
, int asWhat
)
539 type_code
= tvb_get_uint8(tvb
, *offset
);
540 if (type_code
<= ETCH_TC_MAX_TINY_INT
||
541 type_code
>= ETCH_TC_MIN_TINY_INT
) {
542 /* this is the value already */
543 proto_tree_add_item(etch_tree
, asWhat
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
548 increment_dissection_depth(pinfo
);
551 read_struct(offset
, tvb
, etch_tree
, pinfo
, 1);
554 read_array(offset
, tvb
, etch_tree
, pinfo
);
557 read_string(offset
, tvb
, etch_tree
);
560 read_number(offset
, tvb
, etch_tree
, hf_etch_float
, type_code
);
563 read_number(offset
, tvb
, etch_tree
, hf_etch_double
, type_code
);
566 read_number(offset
, tvb
, etch_tree
, hf_etch_short
, type_code
);
569 read_number(offset
, tvb
, etch_tree
, hf_etch_int
, type_code
);
572 read_number(offset
, tvb
, etch_tree
, hf_etch_long
, type_code
);
575 read_number(offset
, tvb
, etch_tree
, hf_etch_byte
, type_code
);
578 read_bytes(offset
, tvb
, etch_tree
);
581 read_number(offset
, tvb
, etch_tree
, asWhat
, type_code
);
583 decrement_dissection_depth(pinfo
);
588 * read a struct and add it to tree
591 // NOLINTNEXTLINE(misc-no-recursion)
592 read_struct(unsigned int *offset
, tvbuff_t
*tvb
, proto_tree
*etch_tree
,
593 packet_info
*pinfo
, int add_type_field
)
596 proto_tree
*new_tree
;
600 ti
= proto_tree_add_item(etch_tree
, hf_etch_struct
, tvb
, *offset
,
601 tvb_captured_length(tvb
) - *offset
, ENC_NA
);
602 new_tree
= proto_item_add_subtree(ti
, ett_etch_struct
);
604 if (add_type_field
) {
605 read_type(offset
, tvb
, new_tree
);
607 /* struct type as hash */
608 read_value(offset
, tvb
, new_tree
, pinfo
, hf_etch_value
);
611 length
= read_value(offset
, tvb
, new_tree
, pinfo
, hf_etch_length
);
613 for (i
= 0; i
< length
; i
++) {
614 read_key_value(offset
, tvb
, new_tree
, pinfo
);
618 read_type(offset
, tvb
, new_tree
);
622 * read a key value pair and add it to tree
625 // NOLINTNEXTLINE(misc-no-recursion)
626 read_key_value(unsigned int *offset
, tvbuff_t
*tvb
, proto_tree
*etch_tree
, packet_info
*pinfo
)
628 proto_tree
*new_tree
;
629 proto_tree
*new_tree_bck
;
630 proto_item
*ti
, *parent_ti
;
632 gbl_have_symbol
= false;
635 proto_tree_add_item(etch_tree
, hf_etch_keyvalue
, tvb
, *offset
, 1,
637 new_tree_bck
= new_tree
=
638 proto_item_add_subtree(parent_ti
, ett_etch_keyvalue
);
640 ti
= proto_tree_add_item(new_tree
, hf_etch_keyname
, tvb
, *offset
, 0,
642 new_tree
= proto_item_add_subtree(ti
, ett_etch_key
);
643 read_value(offset
, tvb
, new_tree
, pinfo
, hf_etch_value
);
645 /* append the symbol of the key */
646 if(gbl_have_symbol
== true){
647 proto_item_append_text(parent_ti
, " (%s)", wmem_strbuf_get_str(gbl_symbol_buffer
));
650 ti
= proto_tree_add_item(new_tree_bck
, hf_etch_valuename
, tvb
, *offset
,
652 new_tree
= proto_item_add_subtree(ti
, ett_etch_value
);
653 read_value(offset
, tvb
, new_tree
, pinfo
, hf_etch_value
);
656 /*************************************************************************/
658 * Preparse the message for the info column
660 static wmem_strbuf_t
*
661 get_column_info(wmem_allocator_t
*scope
, tvbuff_t
*tvb
)
665 wmem_strbuf_t
*result_buf
;
668 /* We've a full PDU: 8 bytes + pdu_packetlen bytes */
669 result_buf
= wmem_strbuf_create(scope
);
671 my_offset
+= (4 + 4 + 1); /* skip Magic, Length, Version */
673 type_code
= tvb_get_uint8(tvb
, my_offset
);
674 byte_length
= get_byte_length(type_code
);
677 if (byte_length
== 4) {
680 hash
= tvb_get_ntohl(tvb
, my_offset
);
681 symbol
= try_val_to_str_ext(hash
, gbl_symbols_vs_ext
);
682 if (symbol
!= NULL
) {
683 wmem_strbuf_append_printf(result_buf
, "%s()", symbol
);
691 /****************************************************************************************************/
693 * main dissector function for an etch message
696 dissect_etch_message(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
698 /* We've a full PDU: 8 bytes + pdu_packetlen bytes */
699 wmem_strbuf_t
*colInfo
= NULL
;
701 if (pinfo
->cinfo
|| tree
) {
702 colInfo
= get_column_info(pinfo
->pool
, tvb
); /* get current symbol */
706 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "ETCH");
709 /* Switch to another frame? => Clear column */
710 if (pinfo
->num
!= gbl_old_frame_num
) {
711 col_clear(pinfo
->cinfo
, COL_INFO
);
714 gbl_old_frame_num
= pinfo
->num
;
716 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s ", wmem_strbuf_get_str(colInfo
));
720 /* we are being asked for details */
723 proto_tree
*etch_tree
;
725 ti
= proto_tree_add_protocol_format(tree
, proto_etch
, tvb
, 0, -1,
726 "ETCH Protocol: %s", wmem_strbuf_get_str(colInfo
));
729 etch_tree
= proto_item_add_subtree(ti
, ett_etch
);
730 proto_tree_add_item(etch_tree
, hf_etch_sig
, tvb
, 0, 4, ENC_BIG_ENDIAN
);
731 proto_tree_add_item(etch_tree
, hf_etch_length
, tvb
, 4, 4, ENC_BIG_ENDIAN
);
732 proto_tree_add_item(etch_tree
, hf_etch_version
, tvb
, 8, 1, ENC_BIG_ENDIAN
);
733 read_struct(&offset
, tvb
, etch_tree
, pinfo
, 0);
736 return tvb_captured_length(tvb
);
740 * determine PDU length of protocol etch
743 get_etch_message_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
,
744 int offset
, void *data _U_
)
746 /* length is at offset 4. we add magic bytes length + length size */
747 return tvb_get_ntohl(tvb
, offset
+ 4) + 8;
752 * main dissector function for the etch protocol
755 dissect_etch(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
757 if (tvb_captured_length(tvb
) < 4) {
758 /* Too small for an etch packet. */
762 if (tvb_memeql(tvb
, 0, etch_magic
, 4) == -1) {
763 /* Not an etch packet. */
767 tcp_dissect_pdus(tvb
, pinfo
, tree
, true, 8, get_etch_message_len
,
768 dissect_etch_message
, data
);
770 if (gbl_pdu_counter
> 0) {
771 col_prepend_fstr(pinfo
->cinfo
, COL_INFO
, "[%d] ", gbl_pdu_counter
+ 1);
778 dissect_etch_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
780 return dissect_etch(tvb
, pinfo
, tree
, data
) > 0;
784 etch_dissector_init(void)
787 gbl_old_frame_num
= 0xFFFFFFFF;
790 void proto_register_etch(void)
792 module_t
*etch_module
;
794 static hf_register_info hf
[] = {
796 {"Etch Signature", "etch.signature",
802 {"Etch Length", "etch.msglength",
808 {"Etch Dim", "etch.dim",
814 {"Etch Version", "etch.version",
820 {"Etch TypeCode", "etch.typecode",
822 VALS(tc_lookup_table
), 0x0,
826 {"Etch Value", "etch.value",
832 {"Etch Bytes", "etch.bytes",
838 {"Etch Byte", "etch.byte",
844 {"Etch Short", "etch.short",
850 {"Etch Int", "etch.int",
856 {"Etch Long", "etch.long",
862 {"Etch Float", "etch.float",
868 {"Etch Double", "etch.double",
869 FT_DOUBLE
, BASE_NONE
,
874 {"Etch keyValue", "etch.keyvalue",
881 {"Etch key", "etch.key",
888 {"Etch symbol", "etch.symbol",
894 {"Etch Struct", "etch.struct",
900 {"Etch String", "etch.string",
901 FT_STRING
, BASE_NONE
,
906 {"Etch key", "etch.keyname",
912 {"Etch value", "etch.valuename",
919 /* Setup protocol subtree array */
920 static int *ett
[] = {
928 proto_etch
= proto_register_protocol("Apache Etch Protocol", "Etch", "etch");
930 proto_register_field_array(proto_etch
, hf
, array_length(hf
));
931 proto_register_subtree_array(ett
, array_length(ett
));
932 etch_handle
= register_dissector("etch", dissect_etch
, proto_etch
);
934 register_init_routine(&etch_dissector_init
);
936 etch_module
= prefs_register_protocol(proto_etch
, proto_reg_handoff_etch
);
938 prefs_register_directory_preference(etch_module
, "file",
939 "Apache Etch symbol folder",
940 "Place the hash/symbol files "
941 "(generated by the Apache Etch compiler) "
942 "ending with .ewh here",
946 void proto_reg_handoff_etch(void)
948 static bool etch_prefs_initialized
= false;
950 /* create dissector handle only once */
951 if(!etch_prefs_initialized
) {
952 /* add heuristic dissector for tcp */
953 heur_dissector_add("tcp", dissect_etch_heur
, "Etch over TCP", "etch_tcp", proto_etch
, HEURISTIC_ENABLE
);
954 dissector_add_for_decode_as_with_preference("tcp.port", etch_handle
);
955 etch_prefs_initialized
= true;
960 /* read config folder files, if filename has changed
961 * (while protecting strcmp() from NULLs)
963 if((gbl_keytab_folder
== NULL
) || (gbl_current_keytab_folder
== NULL
) ||
964 (strcmp(gbl_keytab_folder
, gbl_current_keytab_folder
) != 0)) {
965 read_hashed_symbols_from_dir(gbl_keytab_folder
);
970 * Editor modelines - https://www.wireshark.org/tools/modelines.html
975 * indent-tabs-mode: nil
978 * vi: set shiftwidth=2 tabstop=8 expandtab:
979 * :indentSize=2:tabSize=8:noTabs=true: