2 * Erlang Distribution Protocol
3 * http://www.erlang.org/doc/apps/erts/erl_dist_protocol.html
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * SPDX-License-Identifier: GPL-2.0-or-later
17 #include <epan/packet.h>
19 #include <epan/reassemble.h>
20 #include "packet-tcp.h"
21 #include "packet-epmd.h"
23 #define ERL_PASS_THROUGH 'p'
25 #define VERSION_MAGIC 131 /* 130 in erlang 4.2 */
27 #define SMALL_INTEGER_EXT 'a'
28 #define INTEGER_EXT 'b'
31 #define ATOM_UTF8_EXT 'v'
32 #define SMALL_ATOM_EXT 's'
33 #define SMALL_ATOM_UTF8_EXT 'w'
34 #define REFERENCE_EXT 'e'
35 #define NEW_REFERENCE_EXT 'r'
36 #define NEWER_REFERENCE_EXT 'Z'
38 #define NEW_PORT_EXT 'Y'
39 #define V4_PORT_EXT 'x'
40 #define NEW_FLOAT_EXT 'F'
42 #define NEW_PID_EXT 'X'
43 #define SMALL_TUPLE_EXT 'h'
44 #define LARGE_TUPLE_EXT 'i'
46 #define STRING_EXT 'k'
48 #define BINARY_EXT 'm'
49 #define BIT_BINARY_EXT 'M'
50 #define SMALL_BIG_EXT 'n'
51 #define LARGE_BIG_EXT 'o'
52 #define NEW_FUN_EXT 'p'
53 #define EXPORT_EXT 'q'
58 #define DIST_HEADER 'D'
59 #define DIST_FRAG_HEADER 'E'
60 #define DIST_FRAG_CONT 'F'
61 #define ATOM_CACHE_REF 'R'
62 #define COMPRESSED 'P'
64 #define PNAME "Erlang Distribution Protocol"
65 #define PSNAME "ErlDP"
66 #define PFNAME "erldp"
68 void proto_register_erldp(void);
69 void proto_reg_handoff_erldp(void);
71 static const value_string etf_tag_vals
[] = {
72 { SMALL_INTEGER_EXT
, "SMALL_INTEGER_EXT" },
73 { INTEGER_EXT
, "INTEGER_EXT" },
74 { FLOAT_EXT
, "FLOAT_EXT" },
75 { ATOM_EXT
, "ATOM_EXT" },
76 { ATOM_UTF8_EXT
, "ATOM_UTF8_EXT" },
77 { SMALL_ATOM_EXT
, "SMALL_ATOM_EXT" },
78 { SMALL_ATOM_UTF8_EXT
, "SMALL_ATOM_UTF8_EXT" },
79 { REFERENCE_EXT
, "REFERENCE_EXT" },
80 { NEW_REFERENCE_EXT
, "NEW_REFERENCE_EXT" },
81 { NEWER_REFERENCE_EXT
, "NEWER_REFERENCE_EXT" },
82 { PORT_EXT
, "PORT_EXT" },
83 { NEW_PORT_EXT
, "NEW_PORT_EXT" },
84 { V4_PORT_EXT
, "V4_PORT_EXT" },
85 { NEW_FLOAT_EXT
, "NEW_FLOAT_EXT" },
86 { PID_EXT
, "PID_EXT" },
87 { NEW_PID_EXT
, "NEW_PID_EXT" },
88 { SMALL_TUPLE_EXT
, "SMALL_TUPLE_EXT" },
89 { LARGE_TUPLE_EXT
, "LARGE_TUPLE_EXT" },
90 { NIL_EXT
, "NIL_EXT" },
91 { STRING_EXT
, "STRING_EXT" },
92 { LIST_EXT
, "LIST_EXT" },
93 { BINARY_EXT
, "BINARY_EXT" },
94 { BIT_BINARY_EXT
, "BIT_BINARY_EXT" },
95 { SMALL_BIG_EXT
, "SMALL_BIG_EXT" },
96 { LARGE_BIG_EXT
, "LARGE_BIG_EXT" },
97 { NEW_FUN_EXT
, "NEW_FUN_EXT" },
98 { EXPORT_EXT
, "EXPORT_EXT" },
99 { FUN_EXT
, "FUN_EXT" },
100 { MAP_EXT
, "MAP_EXT" },
101 { LOCAL_EXT
, "LOCAL_EXT" },
102 { DIST_HEADER
, "DIST_HEADER" },
103 { DIST_FRAG_HEADER
, "DIST_FRAG_HEADER" },
104 { ATOM_CACHE_REF
, "ATOM_CACHE_REF" },
105 { COMPRESSED
, "COMPRESSED" },
109 static const value_string etf_header_tag_vals
[] = {
110 { DIST_HEADER
, "DIST_HEADER" },
111 { DIST_FRAG_HEADER
, "DIST_FRAG_HEADER" },
112 { DIST_FRAG_CONT
, "DIST_FRAG_CONT" },
116 static const value_string erldp_ctlmsg_vals
[] = {
123 { 7, "GROUP_LEADER" },
127 { 16, "REG_SEND_TT" },
130 { 20, "DEMONITOR_P" },
131 { 21, "MONITOR_P_EXIT" },
132 { 22, "SEND_SENDER" },
133 { 23, "SEND_SENDER_TT" },
134 { 24, "PAYLOAD_EXIT" },
135 { 25, "PAYLOAD_EXIT_TT" },
136 { 26, "PAYLOAD_EXIT2" },
137 { 27, "PAYLOAD_EXIT2_TT" },
138 { 28, "PAYLOAD_MONITOR_P_EXIT" },
139 { 29, "SPAWN_REQUEST" },
140 { 30, "SPAWN_REQUEST_TT" },
141 { 31, "SPAWN_REPLY" },
142 { 32, "SPAWN_REPLY_TT" },
146 /* Initialize the protocol and registered fields */
147 static int proto_erldp
;
148 static int hf_erldp_length_2
;
149 static int hf_erldp_length_4
;
150 static int hf_etf_version_magic
;
151 static int hf_erldp_tag
;
152 static int hf_erldp_type
;
153 static int hf_erldp_version
;
154 static int hf_erldp_flags_v5
;
155 static int hf_erldp_flags_v6
;
156 static int hf_erldp_flags_published
;
157 static int hf_erldp_flags_atom_cache
;
158 static int hf_erldp_flags_extended_references
;
159 static int hf_erldp_flags_dist_monitor
;
160 static int hf_erldp_flags_fun_tags
;
161 static int hf_erldp_flags_dist_monitor_name
;
162 static int hf_erldp_flags_hidden_atom_cache
;
163 static int hf_erldp_flags_new_fun_tags
;
164 static int hf_erldp_flags_extended_pids_ports
;
165 static int hf_erldp_flags_export_ptr_tag
;
166 static int hf_erldp_flags_bit_binaries
;
167 static int hf_erldp_flags_new_floats
;
168 static int hf_erldp_flags_unicode_io
;
169 static int hf_erldp_flags_dist_hdr_atom_cache
;
170 static int hf_erldp_flags_small_atom_tags
;
171 static int hf_erldp_flags_ets_compressed
;
172 static int hf_erldp_flags_utf8_atoms
;
173 static int hf_erldp_flags_map_tag
;
174 static int hf_erldp_flags_big_creation
;
175 static int hf_erldp_flags_send_sender
;
176 static int hf_erldp_flags_big_seqtrace_labels
;
177 static int hf_erldp_flags_pending_connect
;
178 static int hf_erldp_flags_exit_payload
;
179 static int hf_erldp_flags_fragments
;
180 static int hf_erldp_flags_handshake_23
;
181 static int hf_erldp_flags_unlink_id
;
182 static int hf_erldp_flags_reserved
;
183 static int hf_erldp_flags_spawn
;
184 static int hf_erldp_flags_name_me
;
185 static int hf_erldp_flags_v4_nc
;
186 static int hf_erldp_flags_alias
;
187 static int hf_erldp_flags_spare
;
188 static int hf_erldp_creation
;
189 static int hf_erldp_challenge
;
190 static int hf_erldp_digest
;
191 static int hf_erldp_nlen
;
192 static int hf_erldp_name
;
193 static int hf_erldp_status
;
194 static int hf_erldp_sequence_id
;
195 static int hf_erldp_fragment_id
;
196 static int hf_erldp_num_atom_cache_refs
;
197 static int hf_erldp_etf_flags
;
198 static int hf_erldp_internal_segment_index
;
199 static int hf_erldp_atom_length
;
200 static int hf_erldp_atom_length2
;
201 static int hf_erldp_atom_text
;
202 static int hf_erldp_string_ext_len
;
203 static int hf_erldp_string_ext
;
204 static int hf_erldp_atom_cache_ref
;
205 static int hf_erldp_small_int_ext
;
206 static int hf_erldp_int_ext
;
207 static int hf_erldp_small_big_ext_len
;
208 static int hf_erldp_large_big_ext_len
;
209 static int hf_erldp_big_ext_int
;
210 static int hf_erldp_big_ext_str
;
211 static int hf_erldp_big_ext_bytes
;
212 static int hf_erldp_float_ext
;
213 static int hf_erldp_new_float_ext
;
214 static int hf_erldp_port_ext_id
;
215 static int hf_erldp_port_ext_v4_id
;
216 static int hf_erldp_port_ext_creation
;
217 static int hf_erldp_pid_ext_id
;
218 static int hf_erldp_pid_ext_serial
;
219 static int hf_erldp_pid_ext_creation
;
220 static int hf_erldp_list_ext_len
;
221 static int hf_erldp_map_ext_len
;
222 static int hf_erldp_binary_ext_len
;
223 static int hf_erldp_binary_ext_bits
;
224 static int hf_erldp_binary_ext
;
225 static int hf_erldp_new_ref_ext_len
;
226 static int hf_erldp_new_ref_ext_creation
;
227 static int hf_erldp_new_ref_ext_id
;
228 static int hf_erldp_fun_ext_num_free
;
229 static int hf_erldp_new_fun_ext_size
;
230 static int hf_erldp_new_fun_ext_arity
;
231 static int hf_erldp_new_fun_ext_uniq
;
232 static int hf_erldp_new_fun_ext_index
;
233 static int hf_erldp_new_fun_ext_num_free
;
235 static int hf_etf_tag
;
236 static int hf_etf_dist_header_tag
;
237 static int hf_etf_dist_header_new_cache
;
238 static int hf_etf_dist_header_segment_index
;
239 static int hf_etf_dist_header_long_atoms
;
240 static int hf_etf_arity4
;
241 static int hf_etf_arity
;
243 static int hf_etf_fragments
;
244 static int hf_etf_fragment
;
245 static int hf_etf_fragment_overlap
;
246 static int hf_etf_fragment_overlap_conflicts
;
247 static int hf_etf_fragment_multiple_tails
;
248 static int hf_etf_fragment_too_long_fragment
;
249 static int hf_etf_fragment_error
;
250 static int hf_etf_fragment_count
;
251 static int hf_etf_reassembled_in
;
252 static int hf_etf_reassembled_length
;
253 static int hf_etf_reassembled_data
;
255 static reassembly_table erldp_reassembly_table
;
257 /* Initialize the subtree pointers */
258 static int ett_erldp
;
259 static int ett_erldp_flags
;
262 static int ett_etf_flags
;
263 static int ett_etf_acrs
;
264 static int ett_etf_acr
;
265 static int ett_etf_tmp
;
267 static int ett_etf_fragment
;
268 static int ett_etf_fragments
;
271 static bool erldp_desegment
= true;
274 static dissector_handle_t erldp_handle
;
276 /* Defragmentation */
277 static const fragment_items etf_frag_items
= {
278 /* Fragment subtrees */
281 /* Fragment fields */
284 &hf_etf_fragment_overlap
,
285 &hf_etf_fragment_overlap_conflicts
,
286 &hf_etf_fragment_multiple_tails
,
287 &hf_etf_fragment_too_long_fragment
,
288 &hf_etf_fragment_error
,
289 &hf_etf_fragment_count
,
290 /* Reassembled in field */
291 &hf_etf_reassembled_in
,
292 /* Reassembled length field */
293 &hf_etf_reassembled_length
,
294 &hf_etf_reassembled_data
,
299 /*--- External Term Format ---*/
301 static int dissect_etf_type(const char *label
, packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, proto_tree
*tree
);
302 static int dissect_etf_pdu_data(packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, proto_tree
*tree
);
304 static int dissect_etf_dist_header(packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, proto_tree
*tree
) {
306 uint8_t flen
, i
, flg
;
307 int flg_offset
, acrs_offset
, acr_offset
;
308 uint32_t atom_txt_len
;
309 bool new_entry
, long_atom
;
310 proto_item
*ti_acrs
, *ti_acr
, *ti_tmp
;
311 proto_tree
*flags_tree
, *acrs_tree
, *acr_tree
;
314 proto_tree_add_item_ret_uint(tree
, hf_erldp_num_atom_cache_refs
, tvb
, offset
, 1, ENC_BIG_ENDIAN
, &num
);
322 ti_tmp
= proto_tree_add_item(tree
, hf_erldp_etf_flags
, tvb
, offset
, flen
, ENC_NA
);
323 flags_tree
= proto_item_add_subtree(ti_tmp
, ett_etf_flags
);
324 for (i
=0; i
<num
; i
++) {
325 flg
= tvb_get_uint8(tvb
, offset
+ i
/ 2);
326 proto_tree_add_boolean_format_value(flags_tree
, hf_etf_dist_header_new_cache
, tvb
, offset
+ i
/ 2, 1,
327 (flg
& (0x08 << 4*(i
%2))), "NewCacheEntryFlag[%2d]: %s",
328 i
, (flg
& (0x08 << 4*(i
%2))) ? "SET" : "---");
329 proto_tree_add_uint_format(flags_tree
, hf_etf_dist_header_segment_index
, tvb
, offset
+ i
/ 2, 1,
330 (flg
& (0x07 << 4*(i
%2))), "SegmentIndex [%2d]: %u",
331 i
, (flg
& (0x07 << 4*(i
%2))));
333 flg
= tvb_get_uint8(tvb
, offset
+ num
/ 2);
334 proto_tree_add_boolean(flags_tree
, hf_etf_dist_header_long_atoms
, tvb
, offset
+ num
/ 2, 1, (flg
& (0x01 << 4*(num
%2))));
335 long_atom
= flg
& (0x01 << 4*(num
%2));
338 acrs_offset
= offset
;
339 acrs_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, 0, ett_etf_acrs
, &ti_acrs
, "AtomCacheRefs");
340 for (i
=0; i
<num
; i
++) {
341 flg
= tvb_get_uint8(tvb
, flg_offset
+ i
/ 2);
342 new_entry
= flg
& (0x08 << 4*(i
%2));
344 acr_tree
= proto_tree_add_subtree_format(acrs_tree
, tvb
, offset
, 0, ett_etf_acr
, &ti_acr
, "AtomCacheRef[%2d]:", i
);
345 proto_tree_add_item_ret_uint(acr_tree
, hf_erldp_internal_segment_index
, tvb
, offset
, 1, ENC_BIG_ENDIAN
, &isi
);
346 proto_item_append_text(ti_acr
, " %3d", isi
);
351 proto_tree_add_item_ret_uint(acr_tree
, hf_erldp_atom_length2
, tvb
, offset
, 2, ENC_BIG_ENDIAN
, &atom_txt_len
);
355 proto_tree_add_item_ret_uint(acr_tree
, hf_erldp_atom_length
, tvb
, offset
, 1, ENC_BIG_ENDIAN
, &atom_txt_len
);
358 proto_tree_add_item_ret_string(acr_tree
, hf_erldp_atom_text
, tvb
, offset
, atom_txt_len
, ENC_NA
|ENC_ASCII
, pinfo
->pool
, &str
);
359 proto_item_append_text(ti_acr
, " - '%s'", str
);
360 offset
+= atom_txt_len
;
361 proto_item_set_len(ti_acr
, offset
- acr_offset
);
363 proto_item_set_len(ti_acrs
, offset
- acrs_offset
);
368 // NOLINTNEXTLINE(misc-no-recursion)
369 static int dissect_etf_tuple_content(bool large
, packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, proto_tree
*tree
, const char **value_str _U_
) {
373 proto_tree_add_item_ret_uint(tree
, hf_etf_arity4
, tvb
, offset
, 4, ENC_BIG_ENDIAN
, &arity
);
376 proto_tree_add_item_ret_uint(tree
, hf_etf_arity
, tvb
, offset
, 1, ENC_BIG_ENDIAN
, &arity
);
379 for (i
=0; i
<arity
; i
++) {
380 offset
= dissect_etf_type(NULL
, pinfo
, tvb
, offset
, tree
);
386 static int dissect_etf_big_ext(tvbuff_t
*tvb
, packet_info
*pinfo
, int offset
, uint32_t len
, proto_tree
*tree
, const char **value_str
) {
390 sign
= tvb_get_uint8(tvb
, offset
);
394 uint64_t big_val
= 0;
397 case 1: big_val
= tvb_get_uint8(tvb
, offset
); break;
398 case 2: big_val
= tvb_get_letohs(tvb
, offset
); break;
399 case 3: big_val
= tvb_get_letoh24(tvb
, offset
); break;
400 case 4: big_val
= tvb_get_letohl(tvb
, offset
); break;
401 case 5: big_val
= tvb_get_letoh40(tvb
, offset
); break;
402 case 6: big_val
= tvb_get_letoh48(tvb
, offset
); break;
403 case 7: big_val
= tvb_get_letoh56(tvb
, offset
); break;
404 case 8: big_val
= tvb_get_letoh64(tvb
, offset
); break;
406 proto_tree_add_uint64_format_value(tree
, hf_erldp_big_ext_int
, tvb
, offset
, len
,
407 big_val
, "%s%" PRIu64
, sign
? "-" : "", big_val
);
409 *value_str
= wmem_strdup_printf(pinfo
->pool
, "%s%" PRIu64
,
410 sign
? "-" : "", big_val
);
412 wmem_strbuf_t
*strbuf
= wmem_strbuf_new_sized(pinfo
->pool
, len
*1+3+1);
414 wmem_strbuf_append(strbuf
, "0x");
415 for (i
= len
- 1; i
>= 0; i
--) {
416 wmem_strbuf_append_printf(strbuf
, "%02x", tvb_get_uint8(tvb
, offset
+ i
));
418 char *buf
= wmem_strbuf_finalize(strbuf
);
420 proto_tree_add_string_format_value(tree
, hf_erldp_big_ext_str
, tvb
, offset
, len
, buf
, "%s", buf
);
425 proto_tree_add_item(tree
, hf_erldp_big_ext_bytes
, tvb
, offset
, len
, ENC_NA
);
430 // NOLINTNEXTLINE(misc-no-recursion)
431 static int dissect_etf_type_content(uint8_t tag
, packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, proto_tree
*tree
, const char **value_str
) {
433 uint32_t len
, i
, uint_val
;
435 const uint8_t *str_val
;
437 increment_dissection_depth(pinfo
);
441 proto_tree_add_item_ret_uint(tree
, hf_erldp_atom_cache_ref
, tvb
, offset
, 1, ENC_BIG_ENDIAN
, &uint_val
);
444 *value_str
= wmem_strdup_printf(pinfo
->pool
, "%d", uint_val
);
447 case SMALL_INTEGER_EXT
:
448 proto_tree_add_item_ret_uint(tree
, hf_erldp_small_int_ext
, tvb
, offset
, 1, ENC_BIG_ENDIAN
, &uint_val
);
451 *value_str
= wmem_strdup_printf(pinfo
->pool
, "%u", uint_val
);
455 proto_tree_add_item_ret_int(tree
, hf_erldp_int_ext
, tvb
, offset
, 4, ENC_BIG_ENDIAN
, &int_val
);
458 *value_str
= wmem_strdup_printf(pinfo
->pool
, "%d", int_val
);
461 case SMALL_BIG_EXT
: {
462 proto_tree_add_item_ret_uint(tree
, hf_erldp_small_big_ext_len
, tvb
, offset
, 1, ENC_BIG_ENDIAN
, &len
);
465 offset
= dissect_etf_big_ext(tvb
, pinfo
, offset
, len
, tree
, value_str
);
469 case LARGE_BIG_EXT
: {
470 proto_tree_add_item_ret_uint(tree
, hf_erldp_large_big_ext_len
, tvb
, offset
, 4, ENC_BIG_ENDIAN
, &len
);
473 offset
= dissect_etf_big_ext(tvb
, pinfo
, offset
, len
, tree
, value_str
);
478 proto_tree_add_item_ret_string(tree
, hf_erldp_float_ext
, tvb
, offset
, 31, ENC_NA
|ENC_UTF_8
, pinfo
->pool
, &str_val
);
481 *value_str
= (const char *)str_val
;
485 proto_tree_add_item(tree
, hf_erldp_new_float_ext
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
487 double new_float_val
= tvb_get_ntohieee_double(tvb
, offset
);
488 *value_str
= wmem_strdup_printf(pinfo
->pool
, "%f", new_float_val
);
494 proto_tree_add_item_ret_uint(tree
, hf_erldp_atom_length2
, tvb
, offset
, 2, ENC_BIG_ENDIAN
, &len
);
496 proto_tree_add_item_ret_string(tree
, hf_erldp_atom_text
, tvb
, offset
, len
, ENC_NA
|ENC_UTF_8
, pinfo
->pool
, &str_val
);
499 *value_str
= (const char *)str_val
;
502 case SMALL_ATOM_UTF8_EXT
:
503 proto_tree_add_item_ret_uint(tree
, hf_erldp_atom_length
, tvb
, offset
, 1, ENC_BIG_ENDIAN
, &len
);
505 proto_tree_add_item_ret_string(tree
, hf_erldp_atom_text
, tvb
, offset
, len
, ENC_NA
|ENC_UTF_8
, pinfo
->pool
, &str_val
);
508 *value_str
= (const char *)str_val
;
512 proto_tree_add_item_ret_uint(tree
, hf_erldp_string_ext_len
, tvb
, offset
, 2, ENC_BIG_ENDIAN
, &len
);
514 proto_tree_add_item_ret_string(tree
, hf_erldp_string_ext
, tvb
, offset
, len
, ENC_NA
|ENC_UTF_8
, pinfo
->pool
, &str_val
);
517 *value_str
= (const char *)str_val
;
521 offset
= dissect_etf_type("Node", pinfo
, tvb
, offset
, tree
);
522 proto_tree_add_item(tree
, hf_erldp_port_ext_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
524 proto_tree_add_item(tree
, hf_erldp_port_ext_creation
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
529 offset
= dissect_etf_type("Node", pinfo
, tvb
, offset
, tree
);
530 proto_tree_add_item(tree
, hf_erldp_port_ext_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
532 proto_tree_add_item(tree
, hf_erldp_port_ext_creation
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
537 offset
= dissect_etf_type("Node", pinfo
, tvb
, offset
, tree
);
538 proto_tree_add_item(tree
, hf_erldp_port_ext_v4_id
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
540 proto_tree_add_item(tree
, hf_erldp_port_ext_creation
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
545 offset
= dissect_etf_type("Node", pinfo
, tvb
, offset
, tree
);
546 proto_tree_add_item(tree
, hf_erldp_pid_ext_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
548 proto_tree_add_item(tree
, hf_erldp_pid_ext_serial
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
550 proto_tree_add_item(tree
, hf_erldp_pid_ext_creation
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
555 offset
= dissect_etf_type("Node", pinfo
, tvb
, offset
, tree
);
556 proto_tree_add_item(tree
, hf_erldp_pid_ext_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
558 proto_tree_add_item(tree
, hf_erldp_pid_ext_serial
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
560 proto_tree_add_item(tree
, hf_erldp_pid_ext_creation
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
564 case SMALL_TUPLE_EXT
:
565 offset
= dissect_etf_tuple_content(false, pinfo
, tvb
, offset
, tree
, value_str
);
568 case LARGE_TUPLE_EXT
:
569 offset
= dissect_etf_tuple_content(true, pinfo
, tvb
, offset
, tree
, value_str
);
576 proto_tree_add_item_ret_uint(tree
, hf_erldp_list_ext_len
, tvb
, offset
, 4, ENC_BIG_ENDIAN
, &len
);
578 for (i
=0; i
<len
; i
++) {
579 offset
= dissect_etf_type(NULL
, pinfo
, tvb
, offset
, tree
);
581 offset
= dissect_etf_type("Tail", pinfo
, tvb
, offset
, tree
);
585 proto_tree_add_item_ret_uint(tree
, hf_erldp_map_ext_len
, tvb
, offset
, 4, ENC_BIG_ENDIAN
, &len
);
587 for (i
=0; i
<len
; i
++) {
589 offset
= dissect_etf_type(NULL
, pinfo
, tvb
, offset
, tree
);
591 offset
= dissect_etf_type(NULL
, pinfo
, tvb
, offset
, tree
);
596 proto_tree_add_item_ret_uint(tree
, hf_erldp_binary_ext_len
, tvb
, offset
, 4, ENC_BIG_ENDIAN
, &len
);
598 proto_tree_add_item(tree
, hf_erldp_binary_ext
, tvb
, offset
, len
, ENC_NA
);
603 proto_tree_add_item_ret_uint(tree
, hf_erldp_binary_ext_len
, tvb
, offset
, 4, ENC_BIG_ENDIAN
, &len
);
605 proto_tree_add_item(tree
, hf_erldp_binary_ext_bits
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
607 proto_tree_add_item(tree
, hf_erldp_binary_ext
, tvb
, offset
, len
, ENC_NA
);
611 case NEW_REFERENCE_EXT
:
612 proto_tree_add_item_ret_uint(tree
, hf_erldp_new_ref_ext_len
, tvb
, offset
, 2, ENC_BIG_ENDIAN
, &len
);
614 offset
= dissect_etf_type("Node", pinfo
, tvb
, offset
, tree
);
615 proto_tree_add_item(tree
, hf_erldp_new_ref_ext_creation
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
617 for (i
=0; i
<len
; i
++) {
618 id
= tvb_get_ntohl(tvb
, offset
);
619 proto_tree_add_uint_format(tree
, hf_erldp_new_ref_ext_id
, tvb
, offset
, 4,
620 id
, "ID[%d]: 0x%08X", i
, id
);
625 case NEWER_REFERENCE_EXT
:
626 proto_tree_add_item_ret_uint(tree
, hf_erldp_new_ref_ext_len
, tvb
, offset
, 2, ENC_BIG_ENDIAN
, &len
);
628 offset
= dissect_etf_type("Node", pinfo
, tvb
, offset
, tree
);
629 proto_tree_add_item(tree
, hf_erldp_new_ref_ext_creation
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
631 for (i
=0; i
<len
; i
++) {
632 id
= tvb_get_ntohl(tvb
, offset
);
633 proto_tree_add_uint_format(tree
, hf_erldp_new_ref_ext_id
, tvb
, offset
, 4,
634 id
, "ID[%d]: 0x%08X", i
, id
);
640 proto_tree_add_item_ret_uint(tree
, hf_erldp_fun_ext_num_free
, tvb
, offset
, 4, ENC_BIG_ENDIAN
, &len
);
642 offset
= dissect_etf_type("Pid", pinfo
, tvb
, offset
, tree
);
643 offset
= dissect_etf_type("Module", pinfo
, tvb
, offset
, tree
);
644 offset
= dissect_etf_type("Index", pinfo
, tvb
, offset
, tree
);
645 offset
= dissect_etf_type("Unique", pinfo
, tvb
, offset
, tree
);
647 for (i
= 0; i
< len
; i
++) {
648 char buf
[ITEM_LABEL_LENGTH
];
649 snprintf(buf
, sizeof(buf
), "Free Var[%u]", i
+ 1);
650 offset
= dissect_etf_type(buf
, pinfo
, tvb
, offset
, tree
);
655 proto_tree_add_item(tree
, hf_erldp_new_fun_ext_size
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
657 proto_tree_add_item(tree
, hf_erldp_new_fun_ext_arity
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
659 proto_tree_add_item(tree
, hf_erldp_new_fun_ext_uniq
, tvb
, offset
, 16, ENC_NA
);
661 proto_tree_add_item(tree
, hf_erldp_new_fun_ext_index
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
663 proto_tree_add_item_ret_uint(tree
, hf_erldp_new_fun_ext_num_free
, tvb
, offset
, 4, ENC_BIG_ENDIAN
, &len
);
665 offset
= dissect_etf_type("Module", pinfo
, tvb
, offset
, tree
);
666 offset
= dissect_etf_type("OldIndex", pinfo
, tvb
, offset
, tree
);
667 offset
= dissect_etf_type("OldUnique", pinfo
, tvb
, offset
, tree
);
668 offset
= dissect_etf_type("Pid", pinfo
, tvb
, offset
, tree
);
670 for (i
= 0; i
< len
; i
++) {
671 char buf
[ITEM_LABEL_LENGTH
];
672 snprintf(buf
, sizeof(buf
), "Free Var[%u]", i
+ 1);
673 offset
= dissect_etf_type(buf
, pinfo
, tvb
, offset
, tree
);
678 offset
= dissect_etf_type("Module", pinfo
, tvb
, offset
, tree
);
679 offset
= dissect_etf_type("Function", pinfo
, tvb
, offset
, tree
);
680 offset
= dissect_etf_type("Arity", pinfo
, tvb
, offset
, tree
);
684 decrement_dissection_depth(pinfo
);
689 static int dissect_etf_pdu_data(packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, proto_tree
*tree
) {
692 if ((tvb_get_uint8(tvb
, offset
) == SMALL_TUPLE_EXT
) && (tvb_get_uint8(tvb
, offset
+ 2) == SMALL_INTEGER_EXT
)) {
693 ctl_op
= tvb_get_uint8(tvb
, offset
+ 3);
694 col_add_str(pinfo
->cinfo
, COL_INFO
, val_to_str(ctl_op
, VALS(erldp_ctlmsg_vals
), "unknown ControlMessage operation (%d)"));
696 offset
= dissect_etf_type("ControlMessage", pinfo
, tvb
, offset
, tree
);
697 if (tvb_reported_length_remaining(tvb
, offset
) > 0)
698 offset
= dissect_etf_type("Message", pinfo
, tvb
, offset
, tree
);
703 static int dissect_etf_pdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, const char *label
) {
708 proto_tree
*etf_tree
;
710 mag
= tvb_get_uint8(tvb
, offset
);
711 if (mag
!= VERSION_MAGIC
) {
715 etf_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, -1, ett_etf
, &ti
, (label
) ? label
: "External Term Format");
717 proto_tree_add_item(etf_tree
, hf_etf_version_magic
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
720 proto_tree_add_item_ret_uint(etf_tree
, hf_etf_dist_header_tag
, tvb
, offset
, 1, ENC_BIG_ENDIAN
, &tag
);
724 proto_item_set_text(ti
, "%s", val_to_str(tag
, VALS(etf_header_tag_vals
), "unknown tag (%d)"));
728 offset
= dissect_etf_dist_header(pinfo
, tvb
, offset
, etf_tree
);
729 proto_item_set_len(ti
, offset
);
731 dissect_etf_pdu_data(pinfo
, tvb
, offset
, tree
);
734 case DIST_FRAG_HEADER
:
737 uint64_t sequence_id
, fragment_id
;
738 bool save_fragmented
;
739 fragment_head
*frag_msg
= NULL
;
740 tvbuff_t
*next_tvb
= NULL
;
743 proto_tree_add_item_ret_uint64(etf_tree
, hf_erldp_sequence_id
, tvb
, offset
, 8, ENC_BIG_ENDIAN
, &sequence_id
);
746 proto_tree_add_item_ret_uint64(etf_tree
, hf_erldp_fragment_id
, tvb
, offset
, 8, ENC_BIG_ENDIAN
, &fragment_id
);
749 save_fragmented
= pinfo
->fragmented
;
751 len_rem
= tvb_reported_length_remaining(tvb
, offset
);
755 pinfo
->fragmented
= true;
757 frag_msg
= fragment_add_seq_next(&erldp_reassembly_table
,
758 tvb
, offset
, pinfo
, (uint32_t)sequence_id
, NULL
,
759 len_rem
, fragment_id
!= 1);
761 next_tvb
= process_reassembled_data(tvb
, offset
, pinfo
,
762 "Reassembled ErlDP", frag_msg
,
763 &etf_frag_items
, NULL
, tree
);
765 if (next_tvb
== NULL
)
766 { /* make a new subset */
767 next_tvb
= tvb_new_subset_remaining(tvb
, offset
);
768 call_data_dissector(next_tvb
, pinfo
, tree
);
769 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " (Fragment ID: %" PRIu64
")", fragment_id
);
773 offset
= dissect_etf_dist_header(pinfo
, next_tvb
, 0, etf_tree
);
774 proto_item_set_len(ti
, offset
);
776 dissect_etf_pdu_data(pinfo
, next_tvb
, offset
, tree
);
777 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " (Reassembled, Fragment ID: %" PRIu64
")", fragment_id
);
780 pinfo
->fragmented
= save_fragmented
;
781 offset
= tvb_reported_length_remaining(tvb
, offset
);
789 static int dissect_etf_versioned_type(const char *label
, packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, proto_tree
*tree
) {
790 if (tvb_get_uint8(tvb
, offset
) != VERSION_MAGIC
) {
791 proto_tree_add_item(tree
, hf_erldp_type
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
792 col_set_str(pinfo
->cinfo
, COL_INFO
, "unknown header format");
797 return dissect_etf_type(label
, pinfo
, tvb
, offset
, tree
);
800 // NOLINTNEXTLINE(misc-no-recursion)
801 static int dissect_etf_type(const char *label
, packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, proto_tree
*tree
) {
805 proto_tree
*etf_tree
;
806 const char *value_str
= NULL
;
808 etf_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, -1, ett_etf
, &ti
, (label
) ? label
: "External Term Format");
810 proto_tree_add_item_ret_uint(etf_tree
, hf_etf_tag
, tvb
, offset
, 1, ENC_BIG_ENDIAN
, &tag
);
814 proto_item_set_text(ti
, "%s", val_to_str(tag
, VALS(etf_tag_vals
), "unknown tag (%d)"));
816 offset
= dissect_etf_type_content(tag
, pinfo
, tvb
, offset
, etf_tree
, &value_str
);
818 proto_item_append_text(ti
, ": %s", value_str
);
820 proto_item_set_len(ti
, offset
- begin
);
825 static bool is_handshake(tvbuff_t
*tvb
, int offset
) {
826 uint32_t len
= tvb_get_ntohs(tvb
, offset
);
827 uint8_t tag
= tvb_get_uint8(tvb
, offset
+ 2);
828 return ((len
> 0) && strchr("nNras", tag
) && (len
== (uint32_t)tvb_captured_length_remaining(tvb
, offset
+ 2)));
831 /*--- dissect_erldp_handshake -------------------------------------------------*/
832 static void dissect_erldp_handshake(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
) {
835 bool is_challenge
= false;
839 static int * const erldp_flags_flags
[] = {
840 &hf_erldp_flags_spare
,
841 &hf_erldp_flags_alias
,
842 &hf_erldp_flags_v4_nc
,
843 &hf_erldp_flags_name_me
,
844 &hf_erldp_flags_spawn
,
845 &hf_erldp_flags_reserved
,
846 &hf_erldp_flags_unlink_id
,
847 &hf_erldp_flags_handshake_23
,
848 &hf_erldp_flags_fragments
,
849 &hf_erldp_flags_exit_payload
,
850 &hf_erldp_flags_pending_connect
,
851 &hf_erldp_flags_big_seqtrace_labels
,
852 &hf_erldp_flags_send_sender
,
853 &hf_erldp_flags_big_creation
,
854 &hf_erldp_flags_map_tag
,
855 &hf_erldp_flags_utf8_atoms
,
856 &hf_erldp_flags_ets_compressed
,
857 &hf_erldp_flags_small_atom_tags
,
858 &hf_erldp_flags_dist_hdr_atom_cache
,
859 &hf_erldp_flags_unicode_io
,
860 &hf_erldp_flags_new_floats
,
861 &hf_erldp_flags_bit_binaries
,
862 &hf_erldp_flags_export_ptr_tag
,
863 &hf_erldp_flags_extended_pids_ports
,
864 &hf_erldp_flags_new_fun_tags
,
865 &hf_erldp_flags_hidden_atom_cache
,
866 &hf_erldp_flags_dist_monitor_name
,
867 &hf_erldp_flags_fun_tags
,
868 &hf_erldp_flags_dist_monitor
,
869 &hf_erldp_flags_extended_references
,
870 &hf_erldp_flags_atom_cache
,
871 &hf_erldp_flags_published
,
875 proto_tree_add_item(tree
, hf_erldp_length_2
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
877 proto_tree_add_item_ret_uint(tree
, hf_erldp_tag
, tvb
, offset
, 1, ENC_ASCII
|ENC_NA
, &tag
);
882 proto_tree_add_item(tree
, hf_erldp_version
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
885 proto_tree_add_bitmask(tree
, tvb
, offset
, hf_erldp_flags_v5
,
886 ett_erldp_flags
, erldp_flags_flags
, ENC_BIG_ENDIAN
);
888 if (tvb_bytes_exist(tvb
, offset
, 4)) {
889 if (!tvb_ascii_isprint(tvb
, offset
, 4)) {
894 proto_tree_add_item(tree
, hf_erldp_challenge
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
897 str_len
= tvb_captured_length_remaining(tvb
, offset
);
898 proto_tree_add_item_ret_string(tree
, hf_erldp_name
, tvb
, offset
, str_len
, ENC_ASCII
|ENC_NA
, pinfo
->pool
, &str
);
899 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%s %s", (is_challenge
) ? "SEND_CHALLENGE" : "SEND_NAME", str
);
903 proto_tree_add_bitmask(tree
, tvb
, offset
, hf_erldp_flags_v6
,
904 ett_erldp_flags
, erldp_flags_flags
, ENC_BIG_ENDIAN
);
906 if (tvb_bytes_exist(tvb
, offset
+ 6, 4)) {
907 if (!tvb_ascii_isprint(tvb
, offset
+ 6, 4)) {
912 proto_tree_add_item(tree
, hf_erldp_challenge
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
915 proto_tree_add_item(tree
, hf_erldp_creation
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
917 proto_tree_add_item_ret_uint(tree
, hf_erldp_nlen
, tvb
, offset
, 2, ENC_BIG_ENDIAN
, &str_len
);
919 proto_tree_add_item_ret_string(tree
, hf_erldp_name
, tvb
, offset
, str_len
, ENC_ASCII
|ENC_NA
, pinfo
->pool
, &str
);
920 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%s %s", (is_challenge
) ? "SEND_CHALLENGE" : "SEND_NAME", str
);
924 proto_tree_add_item(tree
, hf_erldp_challenge
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
926 proto_tree_add_item(tree
, hf_erldp_digest
, tvb
, offset
, 16, ENC_NA
);
928 col_set_str(pinfo
->cinfo
, COL_INFO
, "SEND_CHALLENGE_REPLY");
932 proto_tree_add_item(tree
, hf_erldp_digest
, tvb
, offset
, 16, ENC_NA
);
934 col_set_str(pinfo
->cinfo
, COL_INFO
, "SEND_CHALLENGE_ACK");
938 str_len
= tvb_captured_length_remaining(tvb
, offset
);
939 proto_tree_add_item_ret_string(tree
, hf_erldp_status
, tvb
, offset
, str_len
, ENC_ASCII
|ENC_NA
, pinfo
->pool
, &str
);
940 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "SEND_STATUS %s", str
);
945 /*--- dissect_erldp_pdu -------------------------------------------------*/
946 static int dissect_erldp_pdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
) {
950 proto_tree
*erldp_tree
;
952 tvbuff_t
*next_tvb
= NULL
;
954 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, PSNAME
);
956 ti
= proto_tree_add_item(tree
, proto_erldp
, tvb
, 0, -1, ENC_NA
);
957 erldp_tree
= proto_item_add_subtree(ti
, ett_erldp
);
959 if (is_handshake(tvb
, 0)) {
960 dissect_erldp_handshake(tvb
, pinfo
, erldp_tree
);
961 return tvb_captured_length(tvb
);
966 proto_tree_add_item_ret_uint(erldp_tree
, hf_erldp_length_4
, tvb
, offset
, 4, ENC_BIG_ENDIAN
, &msg_len
);
970 col_set_str(pinfo
->cinfo
, COL_INFO
, "KEEP_ALIVE");
974 type
= tvb_get_uint8(tvb
, offset
);
976 case ERL_PASS_THROUGH
:
977 proto_tree_add_item(erldp_tree
, hf_erldp_type
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
980 offset
= dissect_etf_versioned_type("ControlMessage", pinfo
, tvb
, offset
, erldp_tree
);
981 if (tvb_reported_length_remaining(tvb
, offset
) > 0) {
982 dissect_etf_versioned_type("Message", pinfo
, tvb
, offset
, erldp_tree
);
987 next_tvb
= tvb_new_subset_length_caplen(tvb
, offset
, -1, 4 + msg_len
- offset
);
988 dissect_etf_pdu(next_tvb
, pinfo
, erldp_tree
, "DistributionHeader");
992 proto_tree_add_item(erldp_tree
, hf_erldp_type
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
994 col_set_str(pinfo
->cinfo
, COL_INFO
, "unknown header format");
997 return tvb_captured_length(tvb
);
1000 /*--- get_erldp_pdu_len -------------------------------------------------*/
1001 static unsigned get_erldp_pdu_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
,
1002 int offset
, void *data _U_
)
1004 if (is_handshake(tvb
, offset
))
1005 return 2 + tvb_get_ntohs(tvb
, offset
);
1007 return 4 + tvb_get_ntohl(tvb
, offset
);
1010 /*--- dissect_erldp -------------------------------------------------*/
1012 dissect_erldp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data
) {
1013 tcp_dissect_pdus(tvb
, pinfo
, tree
,
1014 erldp_desegment
, /* desegment or not */
1015 4, /* fixed-length part of the PDU */
1016 get_erldp_pdu_len
, /* routine to get the length of the PDU */
1017 dissect_erldp_pdu
, data
); /* routine to dissect a PDU */
1018 return tvb_captured_length(tvb
);
1021 /*--- proto_register_erldp ----------------------------------------------*/
1022 void proto_register_erldp(void) {
1023 /* module_t *erldp_module; */
1025 /* List of fields */
1026 static hf_register_info hf
[] = {
1027 /*--- Handshake fields ---*/
1028 { &hf_erldp_length_2
, { "Length", "erldp.len",
1029 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1030 "Message Length", HFILL
}},
1031 { &hf_etf_version_magic
, { "VERSION_MAGIC", "erldp.version_magic",
1032 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1034 { &hf_erldp_tag
, { "Tag", "erldp.tag",
1035 FT_CHAR
, BASE_HEX
, NULL
, 0x0,
1037 { &hf_erldp_type
, { "Type", "erldp.type",
1038 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1040 { &hf_erldp_version
, { "Version", "erldp.version",
1041 FT_UINT16
, BASE_DEC
, VALS(epmd_version_vals
), 0x0,
1043 { &hf_erldp_flags_v5
, { "Flags", "erldp.flags_v5",
1044 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
1046 { &hf_erldp_flags_v6
, { "Flags", "erldp.flags_v6",
1047 FT_UINT64
, BASE_HEX
, NULL
, 0x0,
1049 { &hf_erldp_flags_published
, { "Published", "erldp.flags.published",
1050 FT_BOOLEAN
, 64, NULL
, 0x1,
1052 { &hf_erldp_flags_atom_cache
, { "Atom Cache", "erldp.flags.atom_cache",
1053 FT_BOOLEAN
, 64, NULL
, 0x2,
1055 { &hf_erldp_flags_extended_references
, { "Extended References", "erldp.flags.extended_references",
1056 FT_BOOLEAN
, 64, NULL
, 0x4,
1058 { &hf_erldp_flags_dist_monitor
, { "Dist Monitor", "erldp.flags.dist_monitor",
1059 FT_BOOLEAN
, 64, NULL
, 0x8,
1061 { &hf_erldp_flags_fun_tags
, { "Fun Tags", "erldp.flags.fun_tags",
1062 FT_BOOLEAN
, 64, NULL
, 0x10,
1064 { &hf_erldp_flags_dist_monitor_name
, { "Dist Monitor Name", "erldp.flags.dist_monitor_name",
1065 FT_BOOLEAN
, 64, NULL
, 0x20,
1067 { &hf_erldp_flags_hidden_atom_cache
, { "Hidden Atom Cache", "erldp.flags.hidden_atom_cache",
1068 FT_BOOLEAN
, 64, NULL
, 0x40,
1070 { &hf_erldp_flags_new_fun_tags
, { "New Fun Tags", "erldp.flags.new_fun_tags",
1071 FT_BOOLEAN
, 64, NULL
, 0x80,
1073 { &hf_erldp_flags_extended_pids_ports
, { "Extended Pids Ports", "erldp.flags.extended_pids_ports",
1074 FT_BOOLEAN
, 64, NULL
, 0x100,
1076 { &hf_erldp_flags_export_ptr_tag
, { "Export PTR Tag", "erldp.flags.export_ptr_tag",
1077 FT_BOOLEAN
, 64, NULL
, 0x200,
1079 { &hf_erldp_flags_bit_binaries
, { "Bit Binaries", "erldp.flags.bit_binaries",
1080 FT_BOOLEAN
, 64, NULL
, 0x400,
1082 { &hf_erldp_flags_new_floats
, { "New Floats", "erldp.flags.new_floats",
1083 FT_BOOLEAN
, 64, NULL
, 0x800,
1085 { &hf_erldp_flags_unicode_io
, { "Unicode IO", "erldp.flags.unicode_io",
1086 FT_BOOLEAN
, 64, NULL
, 0x1000,
1088 { &hf_erldp_flags_dist_hdr_atom_cache
, { "Dist HDR Atom Cache", "erldp.flags.dist_hdr_atom_cache",
1089 FT_BOOLEAN
, 64, NULL
, 0x2000,
1091 { &hf_erldp_flags_small_atom_tags
, { "Small Atom Tags", "erldp.flags.small_atom_tags",
1092 FT_BOOLEAN
, 64, NULL
, 0x4000,
1094 { &hf_erldp_flags_ets_compressed
, { "ETS Compressed", "erldp.flags.ets_compressed",
1095 FT_BOOLEAN
, 64, NULL
, 0x8000,
1097 { &hf_erldp_flags_utf8_atoms
, { "UTF8 Atoms", "erldp.flags.utf8_atoms",
1098 FT_BOOLEAN
, 64, NULL
, 0x10000,
1100 { &hf_erldp_flags_map_tag
, { "Map Tag", "erldp.flags.map_tag",
1101 FT_BOOLEAN
, 64, NULL
, 0x20000,
1103 { &hf_erldp_flags_big_creation
, { "Big Creation", "erldp.flags.big_creation",
1104 FT_BOOLEAN
, 64, NULL
, 0x40000,
1106 { &hf_erldp_flags_send_sender
, { "Send Sender", "erldp.flags.send_sender",
1107 FT_BOOLEAN
, 64, NULL
, 0x80000,
1109 { &hf_erldp_flags_big_seqtrace_labels
, { "Big Seqtrace Labels", "erldp.flags.big_seqtrace_labels",
1110 FT_BOOLEAN
, 64, NULL
, 0x100000,
1112 { &hf_erldp_flags_pending_connect
, { "Pending Connect", "erldp.flags.pending_connect",
1113 FT_BOOLEAN
, 64, NULL
, 0x200000,
1115 { &hf_erldp_flags_exit_payload
, { "Exit Payload", "erldp.flags.exit_payload",
1116 FT_BOOLEAN
, 64, NULL
, 0x400000,
1118 { &hf_erldp_flags_fragments
, { "Fragments", "erldp.flags.fragments",
1119 FT_BOOLEAN
, 64, NULL
, 0x800000,
1121 { &hf_erldp_flags_handshake_23
, { "Handshake 23", "erldp.flags.handshake_23",
1122 FT_BOOLEAN
, 64, NULL
, 0x1000000,
1124 { &hf_erldp_flags_unlink_id
, { "Unlink Id", "erldp.flags.unlink_id",
1125 FT_BOOLEAN
, 64, NULL
, 0x2000000,
1127 { &hf_erldp_flags_reserved
, { "Reserved", "erldp.flags.reserved",
1128 FT_UINT64
, BASE_DEC
, NULL
, 0xfc000000,
1130 { &hf_erldp_flags_spawn
, { "Spawn", "erldp.flags.spawn",
1131 FT_BOOLEAN
, 64, NULL
, 1ULL << 32,
1133 { &hf_erldp_flags_name_me
, { "Name ME", "erldp.flags.name_me",
1134 FT_BOOLEAN
, 64, NULL
, 1ULL << 33,
1136 { &hf_erldp_flags_v4_nc
, { "V4 NC", "erldp.flags.v4_nc",
1137 FT_BOOLEAN
, 64, NULL
, 1ULL << 34,
1139 { &hf_erldp_flags_alias
, { "Alias", "erldp.flags.alias",
1140 FT_BOOLEAN
, 64, NULL
, 1ULL << 35,
1142 { &hf_erldp_flags_spare
, { "Spare", "erldp.flags.spare",
1143 FT_UINT64
, BASE_DEC
, NULL
, ~(0ULL) << 36,
1145 { &hf_erldp_creation
, { "Creation", "erldp.creation",
1146 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1148 { &hf_erldp_challenge
, { "Challenge", "erldp.challenge",
1149 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
1151 { &hf_erldp_digest
, { "Digest", "erldp.digest",
1152 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1154 { &hf_erldp_nlen
, { "Name Length", "erldp.nlen",
1155 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1157 { &hf_erldp_name
, { "Name", "erldp.name",
1158 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1160 { &hf_erldp_status
, { "Status", "erldp.status",
1161 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1163 { &hf_erldp_sequence_id
, { "Sequence Id", "erldp.sequence_id",
1164 FT_UINT64
, BASE_HEX
, NULL
, 0x0,
1166 { &hf_erldp_fragment_id
, { "Fragment Id", "erldp.fragment_id",
1167 FT_UINT64
, BASE_HEX
, NULL
, 0x0,
1169 { &hf_erldp_num_atom_cache_refs
, { "NumberOfAtomCacheRefs", "erldp.num_atom_cache_refs",
1170 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1172 { &hf_erldp_etf_flags
, { "Flags", "erldp.etf_flags",
1173 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1175 { &hf_erldp_internal_segment_index
, { "InternalSegmentIndex", "erldp.internal_segment_index",
1176 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1178 { &hf_erldp_atom_length
, { "Length", "erldp.atom_length",
1179 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1181 { &hf_erldp_atom_length2
, { "Length", "erldp.atom_length",
1182 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1184 { &hf_erldp_atom_text
, { "AtomText", "erldp.atom_text",
1185 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1187 { &hf_erldp_string_ext_len
, { "Len", "erldp.string_ext_len",
1188 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1190 { &hf_erldp_string_ext
, { "String", "erldp.string_ext",
1191 FT_STRING
, BASE_SHOW_ASCII_PRINTABLE
, NULL
, 0x0,
1193 { &hf_erldp_atom_cache_ref
, { "AtomCacheReferenceIndex", "erldp.atom_cache_ref",
1194 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1196 { &hf_erldp_small_int_ext
, { "Int", "erldp.small_int_ext",
1197 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1199 { &hf_erldp_int_ext
, { "Int", "erldp.int_ext",
1200 FT_INT32
, BASE_DEC
, NULL
, 0x0,
1202 { &hf_erldp_small_big_ext_len
, { "Len", "erldp.small_big_ext_len",
1203 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1205 { &hf_erldp_large_big_ext_len
, { "Len", "erldp.large_big_ext_len",
1206 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1208 { &hf_erldp_big_ext_int
, { "Int", "erldp.big_ext_int",
1209 FT_UINT64
, BASE_DEC
, NULL
, 0x0,
1211 { &hf_erldp_big_ext_str
, { "Int", "erldp.big_ext_str",
1212 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1214 { &hf_erldp_big_ext_bytes
, { "Int", "erldp.big_ext_bytes",
1215 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1217 { &hf_erldp_float_ext
, { "Float", "erldp.float_ext",
1218 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
1220 { &hf_erldp_new_float_ext
, { "Float", "erldp.new_float_ext",
1221 FT_DOUBLE
, BASE_NONE
, NULL
, 0x0,
1223 { &hf_erldp_port_ext_id
, { "ID", "erldp.port_ext.id",
1224 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
1226 { &hf_erldp_port_ext_v4_id
, { "ID", "erldp.port_ext.v4_id",
1227 FT_UINT64
, BASE_HEX
, NULL
, 0x0,
1229 { &hf_erldp_port_ext_creation
, { "Creation", "erldp.port_ext.creation",
1230 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1232 { &hf_erldp_pid_ext_id
, { "ID", "erldp.pid_ext.id",
1233 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
1235 { &hf_erldp_pid_ext_serial
, { "Serial", "erldp.pid_ext.serial",
1236 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1238 { &hf_erldp_pid_ext_creation
, { "Creation", "erldp.pid_ext.creation",
1239 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1241 { &hf_erldp_list_ext_len
, { "Len", "erldp.list_ext.len",
1242 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1244 { &hf_erldp_map_ext_len
, { "Len", "erldp.map_ext.len",
1245 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1247 { &hf_erldp_binary_ext_len
, { "Len", "erldp.binary_ext.len",
1248 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1250 { &hf_erldp_binary_ext_bits
, { "Num bits in last byte", "erldp.binary_ext.bits",
1251 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1253 { &hf_erldp_binary_ext
, { "Binary", "erldp.binary_ext",
1254 FT_BYTES
, BASE_SHOW_ASCII_PRINTABLE
, NULL
, 0x0,
1256 { &hf_erldp_new_ref_ext_len
, { "Len", "erldp.new_ref_ext.len",
1257 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1259 { &hf_erldp_new_ref_ext_creation
, { "Creation", "erldp.new_ref_ext.creation",
1260 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1262 { &hf_erldp_new_ref_ext_id
, { "ID", "erldp.new_ref_ext.id",
1263 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
1265 { &hf_erldp_fun_ext_num_free
, { "Num Free", "erldp.fun_ext.num_free",
1266 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1268 { &hf_erldp_new_fun_ext_size
, { "Size", "erldp.new_fun_ext.size",
1269 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1271 { &hf_erldp_new_fun_ext_arity
, { "Arity", "erldp.new_fun_ext.arity",
1272 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1274 { &hf_erldp_new_fun_ext_uniq
, { "Uniq", "erldp.new_fun_ext.uniq",
1275 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1277 { &hf_erldp_new_fun_ext_index
, { "Index", "erldp.new_fun_ext.index",
1278 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1280 { &hf_erldp_new_fun_ext_num_free
, { "Num Free", "erldp.new_fun_ext.num_free",
1281 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1285 { &hf_erldp_length_4
, { "Length", "erldp.len",
1286 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1287 "Message Length", HFILL
}},
1290 { &hf_etf_tag
, { "Tag", "erldp.etf_tag",
1291 FT_UINT8
, BASE_DEC
, VALS(etf_tag_vals
), 0x0,
1293 { &hf_etf_dist_header_tag
, { "Tag", "erldp.etf_header_tag",
1294 FT_UINT8
, BASE_DEC
, VALS(etf_header_tag_vals
), 0x0,
1297 { &hf_etf_dist_header_new_cache
, { "NewCacheEntryFlag", "erldp.dist_header.new_cache",
1298 FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), 0x08,
1301 { &hf_etf_dist_header_segment_index
, { "SegmentIndex", "erldp.dist_header.segment_index",
1302 FT_UINT8
, BASE_DEC
, NULL
, 0x7,
1305 { &hf_etf_dist_header_long_atoms
, { "LongAtoms", "erldp.dist_header.long_atoms",
1306 FT_BOOLEAN
, 8, TFS(&tfs_yes_no
), 0x12,
1309 { &hf_etf_arity4
, { "Arity", "erldp.arity",
1310 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1313 { &hf_etf_arity
, { "Arity", "erldp.arity",
1314 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1317 { &hf_etf_fragments
, { "Message fragments", "erldp.dist.fragments",
1318 FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
,
1321 { &hf_etf_fragment
, { "Message fragment", "erldp.dist.fragment",
1322 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
1325 { &hf_etf_fragment_overlap
, { "Message fragment overlap", "erldp.dist.fragment.overlap",
1326 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
1329 { &hf_etf_fragment_overlap_conflicts
, { "Message fragment overlapping with conflicting data",
1330 "erldp.dist.fragment.overlap.conflicts",
1331 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
1334 { &hf_etf_fragment_multiple_tails
, { "Message has multiple tail fragments",
1335 "erldp.dist.fragment.multiple_tails",
1336 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
1339 { &hf_etf_fragment_too_long_fragment
, { "Message fragment too long", "erldp.dist.fragment.too_long_fragment",
1340 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
1343 { &hf_etf_fragment_error
, { "Message defragmentation error", "erldp.dist.fragment.error",
1344 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
1347 { &hf_etf_fragment_count
, { "Message fragment count", "erldp.dist.fragment.count",
1348 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1351 { &hf_etf_reassembled_in
, { "Reassembled in", "erldp.dist.reassembled.in",
1352 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
1355 { &hf_etf_reassembled_length
, { "Reassembled length", "erldp.dist.reassembled.length",
1356 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1359 { &hf_etf_reassembled_data
, { "Reassembled data", "erldp.dist.reassembled.data",
1360 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1364 /* List of subtrees */
1365 static int *ett
[] = {
1377 /* Register protocol and dissector */
1378 proto_erldp
= proto_register_protocol(PNAME
, PSNAME
, PFNAME
);
1379 reassembly_table_register(&erldp_reassembly_table
,
1380 &addresses_reassembly_table_functions
);
1382 erldp_handle
= register_dissector(PFNAME
, dissect_erldp
, proto_erldp
);
1384 /* Register fields and subtrees */
1385 proto_register_field_array(proto_erldp
, hf
, array_length(hf
));
1386 proto_register_subtree_array(ett
, array_length(ett
));
1390 /*--- proto_reg_handoff_erldp -------------------------------------------*/
1391 void proto_reg_handoff_erldp(void) {
1393 dissector_add_for_decode_as_with_preference("tcp.port", erldp_handle
);
1397 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1402 * indent-tabs-mode: nil
1405 * ex: set shiftwidth=2 tabstop=8 expandtab:
1406 * :indentSize=2:tabSize=8:noTabs=true: