Bug Summary

File:builds/wireshark/wireshark/epan/dissectors/packet-tcpcl.c
Warning:line 1359, column 9
Value stored to 'sub_item' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name packet-tcpcl.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-22/lib/clang/22 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -isystem /builds/wireshark/wireshark/epan/dissectors -isystem /builds/wireshark/wireshark/build/epan/dissectors -isystem /usr/include/mit-krb5 -isystem /usr/include/libxml2 -isystem /builds/wireshark/wireshark/epan -D CARES_NO_DEPRECATED -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_BUILD_DLL -D WS_DEBUG -D WS_DEBUG_UTF_8 -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-22/lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-nonliteral -std=gnu17 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -fdwarf2-cfi-asm -o /builds/wireshark/wireshark/sbout/2026-07-10-101034-3642-1 -x c /builds/wireshark/wireshark/epan/dissectors/packet-tcpcl.c
1/* packet-tcpcl.c
2 * References:
3 * RFC 7242: https://tools.ietf.org/html/rfc7242
4 * RFC 9174: https://www.rfc-editor.org/rfc/rfc9174.html
5 *
6 * TCPCLv4 portions copyright 2019-2021, Brian Sipos <[email protected]>
7 * TCPCLv3 portions copyright 2006-2007 The MITRE Corporation.
8 * All Rights Reserved.
9 * Approved for Public Release; Distribution Unlimited.
10 * Tracking Number 07-0090.
11 *
12 * The US Government will not be charged any license fee and/or royalties
13 * related to this software. Neither name of The MITRE Corporation; nor the
14 * names of its contributors may be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * Wireshark - Network traffic analyzer
18 * By Gerald Combs <[email protected]>
19 * Copyright 1998 Gerald Combs
20 *
21 * SPDX-License-Identifier: GPL-2.0-or-later
22 */
23
24/*
25 * Modifications were made to this file under designation MFS-33289-1 and
26 * are Copyright 2015 United States Government as represented by NASA
27 * Marshall Space Flight Center. All Rights Reserved.
28 *
29 * Released under the GNU GPL with NASA legal approval granted 2016-06-10.
30 *
31 * The subject software is provided "AS IS" WITHOUT ANY WARRANTY of any kind,
32 * either expressed, implied or statutory and this agreement does not,
33 * in any manner, constitute an endorsement by government agency of any
34 * results, designs or products resulting from use of the subject software.
35 * See the Agreement for the specific language governing permissions and
36 * limitations.
37 */
38
39#include "config.h"
40
41#include <inttypes.h>
42#include <epan/packet.h>
43#include <epan/reassemble.h>
44#include <epan/expert.h>
45#include <epan/tfs.h>
46#include <epan/tvbuff-int.h>
47#include <epan/exceptions.h>
48#include <wsutil/array.h>
49#include "packet-tls-utils.h"
50#include "packet-tcp.h"
51#include "packet-ber.h"
52#include "packet-bpv6.h"
53#include "packet-tcpcl.h"
54
55void proto_register_tcpcl(void);
56void proto_reg_handoff_tcpcl(void);
57
58/// Contact header magic bytes
59static const uint8_t magic[] = {'d', 't', 'n', '!'};
60/// Minimum size of contact header for any version
61static const unsigned minimum_chdr_size = 6;
62
63/// Options for missing contact header handling
64enum AllowContactHeaderMissing {
65 CHDRMSN_DISABLE,
66 CHDRMSN_V3FIRST,
67 CHDRMSN_V3ONLY,
68 CHDRMSN_V4FIRST,
69 CHDRMSN_V4ONLY,
70};
71
72static const enum_val_t chdr_missing_choices[] = {
73 {"disabled", "Disabled", CHDRMSN_DISABLE},
74 {"v4first", "Try TCPCLv4 first", CHDRMSN_V4FIRST},
75 {"v4only", "Only TCPCLv4", CHDRMSN_V4ONLY},
76 {"v3first", "Try TCPCLv3 first", CHDRMSN_V3FIRST},
77 {"v3only", "Only TCPCLv3", CHDRMSN_V3ONLY},
78 {NULL((void*)0), NULL((void*)0), 0},
79};
80
81static int proto_tcpcl;
82static int proto_tcpcl_exts;
83/// Protocol column name
84static const char *const proto_name_tcpcl = "TCPCL";
85
86static int tcpcl_chdr_missing = CHDRMSN_V4FIRST;
87static bool_Bool tcpcl_desegment_transfer = true1;
88static bool_Bool tcpcl_analyze_sequence = true1;
89static bool_Bool tcpcl_decode_bundle = true1;
90
91/* For Reassembling TCP Convergence Layer segments */
92static reassembly_table xfer_reassembly_table;
93
94/// Dissector handles
95static dissector_handle_t tcpcl_handle;
96static dissector_handle_t tls_handle;
97static dissector_handle_t bundle_handle;
98
99/// Extension sub-dissectors
100static dissector_table_t sess_ext_dissectors;
101static dissector_table_t xfer_ext_dissectors;
102
103static const value_string v3_message_type_vals[] = {
104 {((TCPCLV3_DATA_SEGMENT>>4) & 0x0F), "DATA_SEGMENT"},
105 {((TCPCLV3_ACK_SEGMENT>>4) & 0x0F), "ACK_SEGMENT"},
106 {((TCPCLV3_REFUSE_BUNDLE>>4) & 0x0F), "REFUSE_BUNDLE"},
107 {((TCPCLV3_KEEP_ALIVE>>4) & 0x0F), "KEEPALIVE"},
108 {((TCPCLV3_SHUTDOWN>>4) & 0x0F), "SHUTDOWN"},
109 {((TCPCLV3_LENGTH>>4) & 0x0F), "LENGTH"},
110 {0, NULL((void*)0)}
111};
112
113/* Refuse-Bundle Reason-Code Flags as per RFC-7242: Section-5.4 */
114static const value_string v3_refuse_reason_code[] = {
115 {TCPCLV3_REFUSE_REASON_UNKNOWN, "Reason for refusal is unknown"},
116 {TCPCLV3_REFUSE_REASON_RX_COMPLETE, "Complete Bundle Received"},
117 {TCPCLV3_REFUSE_REASON_RX_EXHAUSTED, "Receiver's resources exhausted"},
118 {TCPCLV3_REFUSE_REASON_RX_RETRANSMIT, "Receiver expects re-transmission of bundle"},
119 {0, NULL((void*)0)}
120};
121
122static const value_string v4_message_type_vals[]={
123 {TCPCLV4_MSGTYPE_SESS_INIT, "SESS_INIT"},
124 {TCPCLV4_MSGTYPE_SESS_TERM, "SESS_TERM"},
125 {TCPCLV4_MSGTYPE_MSG_REJECT, "MSG_REJECT"},
126 {TCPCLV4_MSGTYPE_KEEPALIVE, "KEEPALIVE"},
127 {TCPCLV4_MSGTYPE_XFER_SEGMENT, "XFER_SEGMENT"},
128 {TCPCLV4_MSGTYPE_XFER_ACK, "XFER_ACK"},
129 {TCPCLV4_MSGTYPE_XFER_REFUSE, "XFER_REFUSE"},
130 {0, NULL((void*)0)},
131};
132
133static const value_string v4_sess_term_reason_vals[]={
134 {0x00, "Unknown"},
135 {0x01, "Idle timeout"},
136 {0x02, "Version mismatch"},
137 {0x03, "Busy"},
138 {0x04, "Contact Failure"},
139 {0x05, "Resource Exhaustion"},
140 {0, NULL((void*)0)},
141};
142
143static const value_string v4_xfer_refuse_reason_vals[]={
144 {0x00, "Unknown"},
145 {0x01, "Completed"},
146 {0x02, "No Resources"},
147 {0x03, "Retransmit"},
148 {0x04, "Not Acceptable"},
149 {0x05, "Extension Failure"},
150 {0, NULL((void*)0)},
151};
152
153static const value_string v4_msg_reject_reason_vals[]={
154 {0x00, "reserved"},
155 {0x01, "Message Type Unknown"},
156 {0x02, "Message Unsupported"},
157 {0x03, "Message Unexpected"},
158 {0, NULL((void*)0)},
159};
160
161static int hf_chdr_tree;
162static int hf_chdr_magic;
163static int hf_chdr_version;
164static int hf_chdr_related;
165
166/* TCP Convergence Header Variables */
167static int hf_tcpclv3_mhdr;
168static int hf_tcpclv3_pkt_type;
169
170/* Refuse-Bundle reason code */
171static int hf_tcpclv3_refuse_reason_code;
172
173static int hf_tcpclv3_chdr_flags;
174static int hf_tcpclv3_chdr_keep_alive;
175static int hf_tcpclv3_chdr_flags_ack_req;
176static int hf_tcpclv3_chdr_flags_frag_enable;
177static int hf_tcpclv3_chdr_flags_nak;
178static int hf_tcpclv3_chdr_local_eid_length;
179static int hf_tcpclv3_chdr_local_eid;
180
181/* TCP Convergence Data Header Variables */
182static int hf_tcpclv3_data_procflags;
183static int hf_tcpclv3_data_procflags_start;
184static int hf_tcpclv3_data_procflags_end;
185static int hf_tcpclv3_xfer_id;
186static int hf_tcpclv3_data_segment_length;
187static int hf_tcpclv3_data_segment_data;
188
189/* TCP Convergence Ack Variables */
190static int hf_tcpclv3_ack_length;
191
192/* TCP Convergence Shutdown Header Variables */
193static int hf_tcpclv3_shutdown_flags;
194static int hf_tcpclv3_shutdown_flags_reason;
195static int hf_tcpclv3_shutdown_flags_delay;
196static int hf_tcpclv3_shutdown_reason;
197static int hf_tcpclv3_shutdown_delay;
198
199static int hf_tcpclv4_chdr_flags;
200static int hf_tcpclv4_chdr_flags_cantls;
201static int hf_tcpclv4_negotiate_use_tls;
202
203static int hf_tcpclv4_mhdr_tree;
204static int hf_tcpclv4_mhdr_type;
205static int hf_tcpclv4_sess_init_keepalive;
206static int hf_tcpclv4_sess_init_seg_mru;
207static int hf_tcpclv4_sess_init_xfer_mru;
208static int hf_tcpclv4_sess_init_nodeid_len;
209static int hf_tcpclv4_sess_init_nodeid_data;
210static int hf_tcpclv4_sess_init_extlist_len;
211static int hf_tcpclv4_sess_init_related;
212static int hf_tcpclv4_negotiate_keepalive;
213
214static int hf_tcpclv4_sess_term_flags;
215static int hf_tcpclv4_sess_term_flags_reply;
216static int hf_tcpclv4_sess_term_reason;
217static int hf_tcpclv4_sess_term_related;
218
219static int hf_tcpclv4_sessext_tree;
220static int hf_tcpclv4_sessext_flags;
221static int hf_tcpclv4_sessext_flags_crit;
222static int hf_tcpclv4_sessext_type;
223static int hf_tcpclv4_sessext_len;
224static int hf_tcpclv4_sessext_data;
225
226static int hf_tcpclv4_xferext_tree;
227static int hf_tcpclv4_xferext_flags;
228static int hf_tcpclv4_xferext_flags_crit;
229static int hf_tcpclv4_xferext_type;
230static int hf_tcpclv4_xferext_len;
231static int hf_tcpclv4_xferext_data;
232
233static int hf_tcpclv4_xfer_flags;
234static int hf_tcpclv4_xfer_flags_start;
235static int hf_tcpclv4_xfer_flags_end;
236static int hf_tcpclv4_xfer_id;
237static int hf_tcpclv4_xfer_total_len;
238static int hf_tcpclv4_xfer_segment_extlist_len;
239static int hf_tcpclv4_xfer_segment_data_len;
240static int hf_tcpclv4_xfer_segment_data;
241static int hf_tcpclv4_xfer_segment_seen_len;
242static int hf_tcpclv4_xfer_segment_related_start;
243static int hf_tcpclv4_xfer_segment_time_start;
244static int hf_tcpclv4_xfer_segment_related_ack;
245static int hf_tcpclv4_xfer_segment_time_diff;
246static int hf_tcpclv4_xfer_ack_ack_len;
247static int hf_tcpclv4_xfer_ack_related_start;
248static int hf_tcpclv4_xfer_ack_time_start;
249static int hf_tcpclv4_xfer_ack_related_seg;
250static int hf_tcpclv4_xfer_ack_time_diff;
251static int hf_tcpclv4_xfer_refuse_reason;
252static int hf_tcpclv4_xfer_refuse_related_seg;
253static int hf_tcpclv4_msg_reject_reason;
254static int hf_tcpclv4_msg_reject_head;
255
256static int hf_tcpclv4_xferext_transferlen_total_len;
257
258static int hf_othername_bundleeid;
259
260/*TCP Convergence Layer Reassembly boilerplate*/
261static int hf_xfer_segments;
262static int hf_xfer_segment;
263static int hf_xfer_segment_overlap;
264static int hf_xfer_segment_overlap_conflicts;
265static int hf_xfer_segment_multiple_tails;
266static int hf_xfer_segment_too_long_fragment;
267static int hf_xfer_segment_error;
268static int hf_xfer_segment_count;
269static int hf_xfer_reassembled_in;
270static int hf_xfer_reassembled_length;
271static int hf_xfer_reassembled_data;
272
273static hf_register_info hf_tcpcl[] = {
274 {&hf_chdr_tree, {"Contact Header", "tcpcl.contact_hdr", FT_NONE, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
275 {&hf_chdr_magic, {"Protocol Magic", "tcpcl.contact_hdr.magic", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
276 {&hf_chdr_version, {"Version", "tcpcl.contact_hdr.version", FT_UINT8, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
277 {&hf_chdr_related, {"Related Header", "tcpcl.contact_hdr.related", FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
278
279 {&hf_tcpclv3_mhdr,
280 {"TCPCLv3 Message", "tcpcl.mhdr",
281 FT_NONE, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}
282 },
283 {&hf_tcpclv3_pkt_type,
284 {"Message Type", "tcpcl.pkt_type",
285 FT_UINT8, BASE_DEC, VALS(v3_message_type_vals)((0 ? (const struct _value_string*)0 : ((v3_message_type_vals
))))
, 0xF0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}
286 },
287 {&hf_tcpclv3_refuse_reason_code,
288 {"Reason-Code", "tcpcl.refuse.reason_code",
289 FT_UINT8, BASE_DEC, VALS(v3_refuse_reason_code)((0 ? (const struct _value_string*)0 : ((v3_refuse_reason_code
))))
, 0x0F, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}
290 },
291 {&hf_tcpclv3_data_procflags,
292 {"Data Flags", "tcpcl.data.proc.flag",
293 FT_UINT8, BASE_HEX, NULL((void*)0), TCPCLV3_DATA_FLAGS, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}
294 },
295 {&hf_tcpclv3_data_procflags_start,
296 {"Segment contains start of bundle", "tcpcl.data.proc.start",
297 FT_BOOLEAN, 8, TFS(&tfs_set_notset)((0 ? (const struct true_false_string*)0 : ((&tfs_set_notset
))))
, TCPCLV3_DATA_START_FLAG, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}
298 },
299 {&hf_tcpclv3_data_procflags_end,
300 {"Segment contains end of Bundle", "tcpcl.data.proc.end",
301 FT_BOOLEAN, 8, TFS(&tfs_set_notset)((0 ? (const struct true_false_string*)0 : ((&tfs_set_notset
))))
, TCPCLV3_DATA_END_FLAG, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}
302 },
303 {&hf_tcpclv3_xfer_id, {"Implied Transfer ID", "tcpcl.xfer_id", FT_UINT64, BASE_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
304 {&hf_tcpclv3_data_segment_length,
305 {"Segment Length", "tcpcl.data.length",
306 FT_UINT64, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}
307 },
308 {&hf_tcpclv3_data_segment_data,
309 {"Segment Data", "tcpcl.data",
310 FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}
311 },
312 {&hf_tcpclv3_shutdown_flags,
313 {"TCP Convergence Shutdown Flags", "tcpcl.shutdown.flags",
314 FT_UINT8, BASE_HEX, NULL((void*)0), TCPCLV3_SHUTDOWN_FLAGS, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}
315 },
316 {&hf_tcpclv3_shutdown_flags_reason,
317 {"Shutdown includes Reason Code", "tcpcl.shutdown.reason.flag",
318 FT_BOOLEAN, 8, TFS(&tfs_set_notset)((0 ? (const struct true_false_string*)0 : ((&tfs_set_notset
))))
, TCPCLV3_SHUTDOWN_REASON, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}
319 },
320 {&hf_tcpclv3_shutdown_flags_delay,
321 {"Shutdown includes Reconnection Delay", "tcpcl.shutdown.delay.flag",
322 FT_BOOLEAN, 8, TFS(&tfs_set_notset)((0 ? (const struct true_false_string*)0 : ((&tfs_set_notset
))))
, TCPCLV3_SHUTDOWN_DELAY, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}
323 },
324 {&hf_tcpclv3_shutdown_reason,
325 {"Shutdown Reason Code", "tcpcl.shutdown.reason",
326 FT_UINT8, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}
327 },
328 {&hf_tcpclv3_shutdown_delay,
329 {"Shutdown Reconnection Delay", "tcpcl.shutdown.delay",
330 FT_UINT16, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}
331 },
332 {&hf_tcpclv3_ack_length,
333 {"Ack Length", "tcpcl.ack.length",
334 FT_UINT64, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}
335 },
336 {&hf_tcpclv3_chdr_flags,
337 {"Flags", "tcpcl.contact_hdr.flags",
338 FT_UINT8, BASE_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}
339 },
340 {&hf_tcpclv3_chdr_flags_ack_req,
341 {"Bundle Acks Requested", "tcpcl.contact_hdr.flags.ackreq",
342 FT_BOOLEAN, 8, TFS(&tfs_set_notset)((0 ? (const struct true_false_string*)0 : ((&tfs_set_notset
))))
, TCPCLV3_BUNDLE_ACK_FLAG, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}
343 },
344 {&hf_tcpclv3_chdr_flags_frag_enable,
345 {"Reactive Fragmentation Enabled", "tcpcl.contact_hdr.flags.fragen",
346 FT_BOOLEAN, 8, TFS(&tfs_set_notset)((0 ? (const struct true_false_string*)0 : ((&tfs_set_notset
))))
, TCPCLV3_REACTIVE_FRAG_FLAG, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}
347 },
348 {&hf_tcpclv3_chdr_flags_nak,
349 {"Support Negative Acknowledgements", "tcpcl.contact_hdr.flags.nak",
350 FT_BOOLEAN, 8, TFS(&tfs_set_notset)((0 ? (const struct true_false_string*)0 : ((&tfs_set_notset
))))
, TCPCLV3_CONNECTOR_RCVR_FLAG, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}
351 },
352 {&hf_tcpclv3_chdr_keep_alive,
353 {"Keep Alive", "tcpcl.contact_hdr.keep_alive",
354 FT_UINT16, BASE_DEC|BASE_UNIT_STRING0x00001000, UNS(&units_seconds)((0 ? (const struct unit_name_string*)0 : ((&units_seconds
))))
, 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}
355 },
356 {&hf_tcpclv3_chdr_local_eid,
357 {"Local EID", "tcpcl.contact_hdr.local_eid",
358 FT_STRING, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}
359 },
360 {&hf_tcpclv3_chdr_local_eid_length,
361 {"Local EID Length", "tcpcl.contact_hdr.local_eid_length",
362 FT_UINT64, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}
363 },
364
365 {&hf_tcpclv4_chdr_flags, {"Contact Flags", "tcpcl.v4.chdr.flags", FT_UINT8, BASE_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
366 {&hf_tcpclv4_chdr_flags_cantls, {"CAN_TLS", "tcpcl.v4.chdr.flags.can_tls", FT_BOOLEAN, 8, TFS(&tfs_set_notset)((0 ? (const struct true_false_string*)0 : ((&tfs_set_notset
))))
, TCPCLV4_CONTACT_FLAG_CANTLS, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
367 // Contact negotiation results
368 {&hf_tcpclv4_negotiate_use_tls, {"Negotiated Use TLS", "tcpcl.v4.negotiated.use_tls", FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
369
370 {&hf_tcpclv4_mhdr_tree, {"TCPCLv4 Message", "tcpcl.v4.mhdr", FT_NONE, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
371 {&hf_tcpclv4_mhdr_type, {"Message Type", "tcpcl.v4.mhdr.type", FT_UINT8, BASE_HEX, VALS(v4_message_type_vals)((0 ? (const struct _value_string*)0 : ((v4_message_type_vals
))))
, 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
372
373 // Session extension fields
374 {&hf_tcpclv4_sessext_tree, {"Session Extension Item", "tcpcl.v4.sessext", FT_PROTOCOL, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
375 {&hf_tcpclv4_sessext_flags, {"Item Flags", "tcpcl.v4.sessext.flags", FT_UINT8, BASE_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
376 {&hf_tcpclv4_sessext_flags_crit, {"CRITICAL", "tcpcl.v4.sessext.flags.critical", FT_BOOLEAN, 8, TFS(&tfs_set_notset)((0 ? (const struct true_false_string*)0 : ((&tfs_set_notset
))))
, TCPCLV4_EXTENSION_FLAG_CRITICAL, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
377 {&hf_tcpclv4_sessext_type, {"Item Type", "tcpcl.v4.sessext.type", FT_UINT16, BASE_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
378 {&hf_tcpclv4_sessext_len, {"Item Length", "tcpcl.v4.sessext.len", FT_UINT32, BASE_DEC|BASE_UNIT_STRING0x00001000, UNS(&units_octet_octets)((0 ? (const struct unit_name_string*)0 : ((&units_octet_octets
))))
, 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
379 {&hf_tcpclv4_sessext_data, {"Type-Specific Data", "tcpcl.v4.sessext.data", FT_NONE, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
380
381 // Transfer extension fields
382 {&hf_tcpclv4_xferext_tree, {"Transfer Extension Item", "tcpcl.v4.xferext", FT_PROTOCOL, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
383 {&hf_tcpclv4_xferext_flags, {"Item Flags", "tcpcl.v4.xferext.flags", FT_UINT8, BASE_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
384 {&hf_tcpclv4_xferext_flags_crit, {"CRITICAL", "tcpcl.v4.xferext.flags.critical", FT_BOOLEAN, 8, TFS(&tfs_set_notset)((0 ? (const struct true_false_string*)0 : ((&tfs_set_notset
))))
, TCPCLV4_EXTENSION_FLAG_CRITICAL, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
385 {&hf_tcpclv4_xferext_type, {"Item Type", "tcpcl.v4.xferext.type", FT_UINT16, BASE_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
386 {&hf_tcpclv4_xferext_len, {"Item Length", "tcpcl.v4.xferext.len", FT_UINT32, BASE_DEC|BASE_UNIT_STRING0x00001000, UNS(&units_octet_octets)((0 ? (const struct unit_name_string*)0 : ((&units_octet_octets
))))
, 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
387 {&hf_tcpclv4_xferext_data, {"Type-Specific Data", "tcpcl.v4.xferext.data", FT_NONE, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
388
389 // SESS_INIT fields
390 {&hf_tcpclv4_sess_init_keepalive, {"Keepalive Interval", "tcpcl.v4.sess_init.keepalive", FT_UINT16, BASE_DEC|BASE_UNIT_STRING0x00001000, UNS(&units_seconds)((0 ? (const struct unit_name_string*)0 : ((&units_seconds
))))
, 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
391 {&hf_tcpclv4_sess_init_seg_mru, {"Segment MRU", "tcpcl.v4.sess_init.seg_mru", FT_UINT64, BASE_DEC|BASE_UNIT_STRING0x00001000, UNS(&units_octet_octets)((0 ? (const struct unit_name_string*)0 : ((&units_octet_octets
))))
, 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
392 {&hf_tcpclv4_sess_init_xfer_mru, {"Transfer MRU", "tcpcl.v4.sess_init.xfer_mru", FT_UINT64, BASE_DEC|BASE_UNIT_STRING0x00001000, UNS(&units_octet_octets)((0 ? (const struct unit_name_string*)0 : ((&units_octet_octets
))))
, 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
393 {&hf_tcpclv4_sess_init_nodeid_len, {"Node ID Length", "tcpcl.v4.sess_init.nodeid_len", FT_UINT16, BASE_DEC|BASE_UNIT_STRING0x00001000, UNS(&units_octet_octets)((0 ? (const struct unit_name_string*)0 : ((&units_octet_octets
))))
, 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
394 {&hf_tcpclv4_sess_init_nodeid_data, {"Node ID Data (UTF8)", "tcpcl.v4.sess_init.nodeid_data", FT_STRING, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
395 {&hf_tcpclv4_sess_init_extlist_len, {"Extension Items Length", "tcpcl.v4.sess_init.extlist_len", FT_UINT32, BASE_DEC|BASE_UNIT_STRING0x00001000, UNS(&units_octet_octets)((0 ? (const struct unit_name_string*)0 : ((&units_octet_octets
))))
, 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
396 {&hf_tcpclv4_sess_init_related, {"Related SESS_INIT", "tcpcl.v4.sess_init.related", FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
397 // Session negotiation results
398 {&hf_tcpclv4_negotiate_keepalive, {"Negotiated Keepalive Interval", "tcpcl.v4.negotiated.keepalive", FT_UINT16, BASE_DEC|BASE_UNIT_STRING0x00001000, UNS(&units_seconds)((0 ? (const struct unit_name_string*)0 : ((&units_seconds
))))
, 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
399 // SESS_TERM fields
400 {&hf_tcpclv4_sess_term_flags, {"Flags", "tcpcl.v4.sess_term.flags", FT_UINT8, BASE_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
401 {&hf_tcpclv4_sess_term_flags_reply, {"REPLY", "tcpcl.v4.sess_term.flags.reply", FT_BOOLEAN, 8, TFS(&tfs_set_notset)((0 ? (const struct true_false_string*)0 : ((&tfs_set_notset
))))
, TCPCLV4_SESS_TERM_FLAG_REPLY, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
402 {&hf_tcpclv4_sess_term_reason, {"Reason", "tcpcl.v4.ses_term.reason", FT_UINT8, BASE_DEC, VALS(v4_sess_term_reason_vals)((0 ? (const struct _value_string*)0 : ((v4_sess_term_reason_vals
))))
, 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
403 {&hf_tcpclv4_sess_term_related, {"Related SESS_TERM", "tcpcl.v4.ses_term.related", FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
404
405 // Common transfer fields
406 {&hf_tcpclv4_xfer_flags, {"Transfer Flags", "tcpcl.v4.xfer_flags", FT_UINT8, BASE_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
407 {&hf_tcpclv4_xfer_flags_start, {"START", "tcpcl.v4.xfer_flags.start", FT_BOOLEAN, 8, TFS(&tfs_set_notset)((0 ? (const struct true_false_string*)0 : ((&tfs_set_notset
))))
, TCPCLV4_TRANSFER_FLAG_START, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
408 {&hf_tcpclv4_xfer_flags_end, {"END", "tcpcl.v4.xfer_flags.end", FT_BOOLEAN, 8, TFS(&tfs_set_notset)((0 ? (const struct true_false_string*)0 : ((&tfs_set_notset
))))
, TCPCLV4_TRANSFER_FLAG_END, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
409 {&hf_tcpclv4_xfer_id, {"Transfer ID", "tcpcl.v4.xfer_id", FT_UINT64, BASE_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
410 {&hf_tcpclv4_xfer_total_len, {"Expected Total Length", "tcpcl.v4.xfer.total_len", FT_UINT64, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
411 // XFER_SEGMENT fields
412 {&hf_tcpclv4_xfer_segment_extlist_len, {"Extension Items Length", "tcpcl.v4.xfer_segment.extlist_len", FT_UINT32, BASE_DEC|BASE_UNIT_STRING0x00001000, UNS(&units_octet_octets)((0 ? (const struct unit_name_string*)0 : ((&units_octet_octets
))))
, 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
413 {&hf_tcpclv4_xfer_segment_data_len, {"Segment Length", "tcpcl.v4.xfer_segment.data_len", FT_UINT64, BASE_DEC|BASE_UNIT_STRING0x00001000, UNS(&units_octet_octets)((0 ? (const struct unit_name_string*)0 : ((&units_octet_octets
))))
, 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
414 {&hf_tcpclv4_xfer_segment_data, {"Segment Data", "tcpcl.v4.xfer_segment.data", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
415 {&hf_tcpclv4_xfer_segment_seen_len, {"Seen Length", "tcpcl.v4.xfer_segment.seen_len", FT_UINT64, BASE_DEC|BASE_UNIT_STRING0x00001000, UNS(&units_octet_octets)((0 ? (const struct unit_name_string*)0 : ((&units_octet_octets
))))
, 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
416 {&hf_tcpclv4_xfer_segment_related_start, {"Related XFER_SEGMENT start", "tcpcl.v4.xfer_segment.related_start", FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
417 {&hf_tcpclv4_xfer_segment_time_start, {"Time since transfer Start", "tcpcl.v4.xfer_segment.time_since_start", FT_RELATIVE_TIME, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
418 {&hf_tcpclv4_xfer_segment_related_ack, {"Related XFER_ACK", "tcpcl.v4.xfer_segment.related_ack", FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
419 {&hf_tcpclv4_xfer_segment_time_diff, {"Acknowledgment Time", "tcpcl.v4.xfer_segment.time_diff", FT_RELATIVE_TIME, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
420 // XFER_ACK fields
421 {&hf_tcpclv4_xfer_ack_ack_len, {"Acknowledged Length", "tcpcl.v4.xfer_ack.ack_len", FT_UINT64, BASE_DEC|BASE_UNIT_STRING0x00001000, UNS(&units_octet_octets)((0 ? (const struct unit_name_string*)0 : ((&units_octet_octets
))))
, 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
422 {&hf_tcpclv4_xfer_ack_related_start, {"Related XFER_SEGMENT start", "tcpcl.v4.xfer_ack.related_start", FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
423 {&hf_tcpclv4_xfer_ack_time_start, {"Time since transfer Start", "tcpcl.v4.xfer_ack.time_since_start", FT_RELATIVE_TIME, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
424 {&hf_tcpclv4_xfer_ack_related_seg, {"Related XFER_SEGMENT", "tcpcl.v4.xfer_ack.related_seg", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_ACK)((gpointer) (glong) (FT_FRAMENUM_ACK)), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
425 {&hf_tcpclv4_xfer_ack_time_diff, {"Acknowledgment Time", "tcpcl.v4.xfer_ack.time_diff", FT_RELATIVE_TIME, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
426 // XFER_REFUSE fields
427 {&hf_tcpclv4_xfer_refuse_reason, {"Reason", "tcpcl.v4.xfer_refuse.reason", FT_UINT8, BASE_DEC, VALS(v4_xfer_refuse_reason_vals)((0 ? (const struct _value_string*)0 : ((v4_xfer_refuse_reason_vals
))))
, 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
428 {&hf_tcpclv4_xfer_refuse_related_seg, {"Related XFER_SEGMENT", "tcpcl.v4.xfer_refuse.related_seg", FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
429 // MSG_REJECT fields
430 {&hf_tcpclv4_msg_reject_reason, {"Reason", "tcpcl.v4.msg_reject.reason", FT_UINT8, BASE_DEC, VALS(v4_msg_reject_reason_vals)((0 ? (const struct _value_string*)0 : ((v4_msg_reject_reason_vals
))))
, 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
431 {&hf_tcpclv4_msg_reject_head, {"Rejected Type", "tcpcl.v4.msg_reject.head", FT_UINT8, BASE_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
432
433 // Specific extensions
434 {&hf_tcpclv4_xferext_transferlen_total_len, {"Total Length", "tcpcl.v4.xferext.transfer_length.total_len", FT_UINT64, BASE_DEC|BASE_UNIT_STRING0x00001000, UNS(&units_octet_octets)((0 ? (const struct unit_name_string*)0 : ((&units_octet_octets
))))
, 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
435 // PKIX other name form
436 {&hf_othername_bundleeid, {"BundleEID", "tcpcl.v4.BundleEID", FT_STRING, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
437
438 {&hf_xfer_segments,
439 {"TCPCL transfer segments", "tcpcl.xfer.fragments",
440 FT_NONE, BASE_NONE, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
441 {&hf_xfer_segment,
442 {"TCPCL transfer segment", "tcpcl.xfer.fragment",
443 FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
444 {&hf_xfer_segment_overlap,
445 {"Transfer segment overlap", "tcpcl.xfer.fragment.overlap",
446 FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
447 {&hf_xfer_segment_overlap_conflicts,
448 {"Transfer segment overlapping with conflicting data",
449 "tcpcl.xfer.fragment.overlap.conflicts",
450 FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
451 {&hf_xfer_segment_multiple_tails,
452 {"Message has multiple tail segments",
453 "tcpcl.xfer.fragment.multiple_tails",
454 FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
455 {&hf_xfer_segment_too_long_fragment,
456 {"Transfer segment too long", "tcpcl.xfer.fragment.too_long_fragment",
457 FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
458 {&hf_xfer_segment_error,
459 {"Transfer desegmentation error", "tcpcl.xfer.fragment.error",
460 FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
461 {&hf_xfer_segment_count,
462 {"Transfer segment count", "tcpcl.xfer.fragment.count",
463 FT_UINT32, BASE_DEC, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
464 {&hf_xfer_reassembled_in,
465 {"Reassembled in", "tcpcl.xfer.reassembled.in",
466 FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
467 {&hf_xfer_reassembled_length,
468 {"Reassembled length", "tcpcl.xfer.reassembled.length",
469 FT_UINT32, BASE_DEC, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
470 {&hf_xfer_reassembled_data,
471 {"Reassembled data", "tcpcl.xfer.reassembled.data",
472 FT_BYTES, BASE_NONE, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
473
474};
475
476static int *const v3_chdr_flags[] = {
477 &hf_tcpclv3_chdr_flags_ack_req,
478 &hf_tcpclv3_chdr_flags_frag_enable,
479 &hf_tcpclv3_chdr_flags_nak,
480 NULL((void*)0)
481};
482
483static int *const v3_data_procflags[] = {
484 &hf_tcpclv3_data_procflags_start,
485 &hf_tcpclv3_data_procflags_end,
486 NULL((void*)0)
487};
488static int *const v4_chdr_flags[] = {
489 &hf_tcpclv4_chdr_flags_cantls,
490 NULL((void*)0)
491};
492static int *const v4_sess_term_flags[] = {
493 &hf_tcpclv4_sess_term_flags_reply,
494 NULL((void*)0)
495};
496static int *const v4_xfer_flags[] = {
497 &hf_tcpclv4_xfer_flags_start,
498 &hf_tcpclv4_xfer_flags_end,
499 NULL((void*)0)
500};
501static int *const v4_sessext_flags[] = {
502 &hf_tcpclv4_sessext_flags_crit,
503 NULL((void*)0)
504};
505static int *const v4_xferext_flags[] = {
506 &hf_tcpclv4_xferext_flags_crit,
507 NULL((void*)0)
508};
509
510/* Tree Node Variables */
511static int ett_proto_tcpcl;
512static int ett_chdr;
513static int ett_tcpclv3_chdr_flags;
514static int ett_tcpclv3_mhdr;
515static int ett_tcpclv3_data_procflags;
516static int ett_tcpclv3_shutdown_flags;
517static int ett_xfer_segment;
518static int ett_xfer_segments;
519static int ett_tcpclv4_chdr_flags;
520static int ett_tcpclv4_mhdr;
521static int ett_tcpclv4_sess_term_flags;
522static int ett_tcpclv4_xfer_flags;
523static int ett_tcpclv4_sessext;
524static int ett_tcpclv4_sessext_flags;
525static int ett_tcpclv4_sessext_data;
526static int ett_tcpclv4_xferext;
527static int ett_tcpclv4_xferext_flags;
528static int ett_tcpclv4_xferext_data;
529
530static int *ett[] = {
531 &ett_proto_tcpcl,
532 &ett_chdr,
533 &ett_tcpclv3_chdr_flags,
534 &ett_tcpclv3_mhdr,
535 &ett_tcpclv3_data_procflags,
536 &ett_tcpclv3_shutdown_flags,
537 &ett_tcpclv4_chdr_flags,
538 &ett_tcpclv4_mhdr,
539 &ett_tcpclv4_sess_term_flags,
540 &ett_tcpclv4_xfer_flags,
541 &ett_tcpclv4_sessext,
542 &ett_tcpclv4_sessext_flags,
543 &ett_tcpclv4_sessext_data,
544 &ett_tcpclv4_xferext,
545 &ett_tcpclv4_xferext_flags,
546 &ett_tcpclv4_xferext_data,
547 &ett_xfer_segment,
548 &ett_xfer_segments,
549};
550
551static expert_field ei_invalid_magic;
552static expert_field ei_invalid_version;
553static expert_field ei_mismatch_version;
554static expert_field ei_chdr_duplicate;
555static expert_field ei_length_clamped;
556static expert_field ei_chdr_missing;
557
558static expert_field ei_tcpclv3_invalid_msg_type;
559static expert_field ei_tcpclv3_data_flags;
560
561static expert_field ei_tcpclv4_invalid_msg_type;
562static expert_field ei_tcpclv4_invalid_sessext_type;
563static expert_field ei_tcpclv4_invalid_xferext_type;
564static expert_field ei_tcpclv4_extitem_critical;
565static expert_field ei_tcpclv4_sess_init_missing;
566static expert_field ei_tcpclv4_sess_init_duplicate;
567static expert_field ei_tcpclv4_sess_term_duplicate;
568static expert_field ei_tcpclv4_sess_term_reply_flag;
569static expert_field ei_tcpclv4_xfer_seg_over_seg_mru;
570static expert_field ei_tcpclv4_xfer_seg_missing_start;
571static expert_field ei_tcpclv4_xfer_seg_duplicate_start;
572static expert_field ei_tcpclv4_xfer_seg_missing_end;
573static expert_field ei_tcpclv4_xfer_seg_duplicate_end;
574static expert_field ei_tcpclv4_xfer_seg_no_relation;
575static expert_field ei_xfer_seg_over_total_len;
576static expert_field ei_xfer_mismatch_total_len;
577static expert_field ei_xfer_ack_mismatch_flags;
578static expert_field ei_xfer_ack_no_relation;
579static expert_field ei_tcpclv4_xfer_refuse_no_transfer;
580static expert_field ei_tcpclv4_xferload_over_xfer_mru;
581
582static ei_register_info ei_tcpcl[] = {
583 {&ei_invalid_magic, { "tcpcl.invalid_contact_magic", PI_PROTOCOL0x09000000, PI_ERROR0x00800000, "Magic string is invalid", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
584 {&ei_invalid_version, { "tcpcl.invalid_contact_version", PI_PROTOCOL0x09000000, PI_ERROR0x00800000, "Protocol version not handled", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
585 {&ei_mismatch_version, { "tcpcl.mismatch_contact_version", PI_PROTOCOL0x09000000, PI_ERROR0x00800000, "Protocol version mismatch", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
586 {&ei_chdr_duplicate, { "tcpcl.contact_duplicate", PI_SEQUENCE0x02000000, PI_ERROR0x00800000, "Duplicate Contact Header", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
587 {&ei_length_clamped, { "tcpcl.length_clamped", PI_UNDECODED0x05000000, PI_ERROR0x00800000, "Length too large for Wireshark to handle", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
588 {&ei_chdr_missing, { "tcpcl.contact_missing", PI_ASSUMPTION0x0d000000, PI_NOTE0x00400000, "Contact Header is missing, TCPCL version is implied", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
589
590 {&ei_tcpclv3_invalid_msg_type, { "tcpcl.unknown_message_type", PI_UNDECODED0x05000000, PI_ERROR0x00800000, "Message type is unknown", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
591 {&ei_tcpclv3_data_flags, { "tcpcl.data.flags.invalid", PI_PROTOCOL0x09000000, PI_WARN0x00600000, "Invalid TCP CL Data Segment Flags", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
592
593 {&ei_tcpclv4_invalid_msg_type, { "tcpcl.v4.unknown_message_type", PI_UNDECODED0x05000000, PI_ERROR0x00800000, "Message type is unknown", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
594 {&ei_tcpclv4_invalid_sessext_type, { "tcpcl.v4.unknown_sessext_type", PI_UNDECODED0x05000000, PI_WARN0x00600000, "Session Extension type is unknown", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
595 {&ei_tcpclv4_invalid_xferext_type, { "tcpcl.v4.unknown_xferext_type", PI_UNDECODED0x05000000, PI_WARN0x00600000, "Transfer Extension type is unknown", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
596 {&ei_tcpclv4_extitem_critical, { "tcpcl.v4.extitem_critical", PI_REQUEST_CODE0x04000000, PI_CHAT0x00200000, "Extension Item is critical", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
597 {&ei_tcpclv4_sess_init_missing, { "tcpcl.v4.sess_init_missing", PI_SEQUENCE0x02000000, PI_ERROR0x00800000, "Expected SESS_INIT message first", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
598 {&ei_tcpclv4_sess_init_duplicate, { "tcpcl.v4.sess_init_duplicate", PI_SEQUENCE0x02000000, PI_ERROR0x00800000, "Duplicate SESS_INIT message", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
599 {&ei_tcpclv4_sess_term_duplicate, { "tcpcl.v4.sess_term_duplicate", PI_SEQUENCE0x02000000, PI_ERROR0x00800000, "Duplicate SESS_TERM message", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
600 {&ei_tcpclv4_sess_term_reply_flag, { "tcpcl.v4.sess_term_reply_flag", PI_SEQUENCE0x02000000, PI_ERROR0x00800000, "Reply SESS_TERM missing flag", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
601 {&ei_tcpclv4_xfer_seg_over_seg_mru, { "tcpcl.v4.xfer_seg_over_seg_mru", PI_PROTOCOL0x09000000, PI_WARN0x00600000, "Segment data size larger than peer MRU", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
602 {&ei_tcpclv4_xfer_seg_missing_start, { "tcpcl.v4.xfer_seg_missing_start", PI_SEQUENCE0x02000000, PI_ERROR0x00800000, "First XFER_SEGMENT is missing START flag", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
603 {&ei_tcpclv4_xfer_seg_duplicate_start, { "tcpcl.v4.xfer_seg_duplicate_start", PI_SEQUENCE0x02000000, PI_ERROR0x00800000, "Non-first XFER_SEGMENT has START flag", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
604 {&ei_tcpclv4_xfer_seg_missing_end, { "tcpcl.v4.xfer_seg_missing_end", PI_SEQUENCE0x02000000, PI_ERROR0x00800000, "Last XFER_SEGMENT is missing END flag", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
605 {&ei_tcpclv4_xfer_seg_duplicate_end, { "tcpcl.v4.xfer_seg_duplicate_end", PI_SEQUENCE0x02000000, PI_ERROR0x00800000, "Non-last XFER_SEGMENT has END flag", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
606 {&ei_tcpclv4_xfer_seg_no_relation, { "tcpcl.v4.xfer_seg_no_relation", PI_SEQUENCE0x02000000, PI_NOTE0x00400000, "XFER_SEGMENT has no related XFER_ACK", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
607 {&ei_tcpclv4_xfer_refuse_no_transfer, { "tcpcl.v4.xfer_refuse_no_transfer", PI_SEQUENCE0x02000000, PI_NOTE0x00400000, "XFER_REFUSE has no related XFER_SEGMENT(s)", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
608 {&ei_tcpclv4_xferload_over_xfer_mru, { "tcpcl.v4.xferload_over_xfer_mru", PI_SEQUENCE0x02000000, PI_NOTE0x00400000, "Transfer larger than peer MRU", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
609 {&ei_xfer_seg_over_total_len, { "tcpcl.xfer_seg_over_total_len", PI_SEQUENCE0x02000000, PI_ERROR0x00800000, "XFER_SEGMENT has accumulated length beyond the Transfer Length extension", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
610 {&ei_xfer_mismatch_total_len, { "tcpcl.xfer_mismatch_total_len", PI_SEQUENCE0x02000000, PI_ERROR0x00800000, "Transfer has total length different than the Transfer Length extension", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
611 {&ei_xfer_ack_mismatch_flags, { "tcpcl.xfer_ack_mismatch_flags", PI_SEQUENCE0x02000000, PI_ERROR0x00800000, "XFER_ACK does not have flags matching XFER_SEGMENT", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
612 {&ei_xfer_ack_no_relation, { "tcpcl.xfer_ack_no_relation", PI_SEQUENCE0x02000000, PI_NOTE0x00400000, "XFER_ACK has no related XFER_SEGMENT", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
613};
614
615static const fragment_items xfer_frag_items = {
616 /*Fragment subtrees*/
617 &ett_xfer_segment,
618 &ett_xfer_segments,
619 /*Fragment Fields*/
620 &hf_xfer_segments,
621 &hf_xfer_segment,
622 &hf_xfer_segment_overlap,
623 &hf_xfer_segment_overlap_conflicts,
624 &hf_xfer_segment_multiple_tails,
625 &hf_xfer_segment_too_long_fragment,
626 &hf_xfer_segment_error,
627 &hf_xfer_segment_count,
628 /*Reassembled in field*/
629 &hf_xfer_reassembled_in,
630 /*Reassembled length field*/
631 &hf_xfer_reassembled_length,
632 /* Reassembled data field */
633 &hf_xfer_reassembled_data,
634 /*Tag*/
635 "Transfer segments"
636};
637
638static unsigned tvb_get_sdnv(tvbuff_t *tvb, unsigned offset, uint64_t *value) {
639 return tvb_get_varint(tvb, offset, FT_VARINT_MAX_LEN10, value, ENC_VARINT_SDNV0x00000010);
640}
641
642static void tcpcl_frame_loc_init(tcpcl_frame_loc_t *loc, const packet_info *pinfo, tvbuff_t *tvb, const int offset) {
643 loc->frame_num = pinfo->num;
644
645 loc->ds_idx = get_data_source_index_by_tvb(pinfo, tvb_get_ds_tvb(tvb));
646 DISSECTOR_ASSERT(loc->ds_idx >= 0)((void) ((loc->ds_idx >= 0) ? (void)0 : (proto_report_dissector_bug
("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-tcpcl.c"
, 646, "loc->ds_idx >= 0"))))
;
647 loc->raw_offset = tvb_raw_offset(tvb) + offset;
648 DISSECTOR_ASSERT(offset >= 0)((void) ((offset >= 0) ? (void)0 : (proto_report_dissector_bug
("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-tcpcl.c"
, 648, "offset >= 0"))))
;
649}
650
651/** Construct a new object on the file allocator.
652 */
653static tcpcl_frame_loc_t * tcpcl_frame_loc_new(wmem_allocator_t *alloc, const packet_info *pinfo, tvbuff_t *tvb, const int offset) {
654 tcpcl_frame_loc_t *obj = wmem_new(alloc, tcpcl_frame_loc_t)((tcpcl_frame_loc_t*)wmem_alloc((alloc), sizeof(tcpcl_frame_loc_t
)))
;
655 tcpcl_frame_loc_init(obj, pinfo, tvb, offset);
656 return obj;
657}
658
659/** Construct a new object on the file allocator.
660 */
661static tcpcl_frame_loc_t * tcpcl_frame_loc_clone(wmem_allocator_t *alloc, const tcpcl_frame_loc_t *loc) {
662 tcpcl_frame_loc_t *obj = wmem_new(alloc, tcpcl_frame_loc_t)((tcpcl_frame_loc_t*)wmem_alloc((alloc), sizeof(tcpcl_frame_loc_t
)))
;
663 *obj = *loc;
664 return obj;
665}
666
667#define tcpcl_frame_loc_freewmem_free wmem_free
668
669/** Function to match the GCompareDataFunc signature.
670 */
671static int tcpcl_frame_loc_compare(const void *a, const void *b, void *user_data _U___attribute__((unused))) {
672 const tcpcl_frame_loc_t *aloc = a;
673 const tcpcl_frame_loc_t *bloc = b;
674
675 if (aloc->frame_num < bloc->frame_num) {
676 return -1;
677 }
678 else if (aloc->frame_num > bloc->frame_num) {
679 return 1;
680 }
681
682 if (aloc->ds_idx < bloc->ds_idx) {
683 return -1;
684 }
685 else if (aloc->ds_idx > bloc->ds_idx) {
686 return 1;
687 }
688 if (aloc->raw_offset < bloc->raw_offset) {
689 return -1;
690 }
691 else if (aloc->raw_offset > bloc->raw_offset) {
692 return 1;
693 }
694 return 0;
695}
696
697/** Function to match the GCompareFunc signature.
698 */
699static gboolean tcpcl_frame_loc_equal(const void *a, const void *b) {
700 const tcpcl_frame_loc_t *aobj = a;
701 const tcpcl_frame_loc_t *bobj = b;
702 return (
703 (aobj->frame_num == bobj->frame_num)
704 && (aobj->ds_idx == bobj->ds_idx)
705 && (aobj->raw_offset == bobj->raw_offset)
706 );
707}
708
709/** Function to match the GHashFunc signature.
710 */
711static unsigned tcpcl_frame_loc_hash(const void *key) {
712 const tcpcl_frame_loc_t *obj = key;
713 return (
714 g_int_hash(&(obj->frame_num))
715 ^ g_int_hash(&(obj->ds_idx))
716 ^ g_int_hash(&(obj->raw_offset))
717 );
718}
719
720struct tcpcl_ack_meta;
721typedef struct tcpcl_ack_meta tcpcl_ack_meta_t;
722struct tcpcl_seg_meta;
723typedef struct tcpcl_seg_meta tcpcl_seg_meta_t;
724
725struct tcpcl_seg_meta {
726 /// Location associated with this metadata
727 tcpcl_frame_loc_t frame_loc;
728 /// Timestamp on the frame (end time if reassembled)
729 nstime_t frame_time;
730 /// Copy of message flags
731 uint8_t flags;
732 /// Total transfer length including this segment
733 uint64_t seen_len;
734
735 /// Potential related start segment
736 tcpcl_seg_meta_t *related_start;
737 /// Potential related XFER_ACK
738 tcpcl_ack_meta_t *related_ack;
739};
740
741static tcpcl_seg_meta_t * tcpcl_seg_meta_new(const packet_info *pinfo, const tcpcl_frame_loc_t *loc) {
742 tcpcl_seg_meta_t *obj = wmem_new(wmem_file_scope(), tcpcl_seg_meta_t)((tcpcl_seg_meta_t*)wmem_alloc((wmem_file_scope()), sizeof(tcpcl_seg_meta_t
)))
;
743 obj->frame_loc = *loc;
744 obj->frame_time = pinfo->abs_ts;
745 obj->flags = 0;
746 obj->seen_len = 0;
747 obj->related_start = NULL((void*)0);
748 obj->related_ack = NULL((void*)0);
749 return obj;
750}
751
752static void tcpcl_seg_meta_free(tcpcl_seg_meta_t *obj) {
753 wmem_free(wmem_file_scope(), obj);
754}
755
756/** Function to match the GCompareFunc signature.
757 */
758static int tcpcl_seg_meta_compare_loc(const void *a, const void *b) {
759 return tcpcl_frame_loc_compare(
760 &(((tcpcl_seg_meta_t *)a)->frame_loc),
761 &(((tcpcl_seg_meta_t *)b)->frame_loc),
762 NULL((void*)0)
763 );
764}
765
766struct tcpcl_ack_meta {
767 /// Location associated with this metadata
768 tcpcl_frame_loc_t frame_loc;
769 /// Timestamp on the frame (end time if reassembled)
770 nstime_t frame_time;
771 /// Copy of message flags
772 uint8_t flags;
773 /// Total acknowledged length including this ack
774 uint64_t seen_len;
775
776 /// Potential related start segment
777 tcpcl_seg_meta_t *related_start;
778 /// Potential related XFER_SEGMENT
779 tcpcl_seg_meta_t *related_seg;
780};
781
782static tcpcl_ack_meta_t * tcpcl_ack_meta_new(const packet_info *pinfo, const tcpcl_frame_loc_t *loc) {
783 tcpcl_ack_meta_t *obj = wmem_new(wmem_file_scope(), tcpcl_ack_meta_t)((tcpcl_ack_meta_t*)wmem_alloc((wmem_file_scope()), sizeof(tcpcl_ack_meta_t
)))
;
784 obj->frame_loc = *loc;
785 obj->frame_time = pinfo->abs_ts;
786 obj->flags = 0;
787 obj->seen_len = 0;
788 obj->related_start = NULL((void*)0);
789 obj->related_seg = NULL((void*)0);
790 return obj;
791}
792
793static void tcpcl_ack_meta_free(tcpcl_ack_meta_t *obj) {
794 wmem_free(wmem_file_scope(), obj);
795}
796
797/** Function to match the GCompareFunc signature.
798 */
799static int tcpcl_ack_meta_compare_loc(const void *a, const void *b) {
800 return tcpcl_frame_loc_compare(
801 &(((tcpcl_seg_meta_t *)a)->frame_loc),
802 &(((tcpcl_seg_meta_t *)b)->frame_loc),
803 NULL((void*)0)
804 );
805}
806
807static tcpcl_transfer_t * tcpcl_transfer_new(void) {
808 tcpcl_transfer_t *obj = wmem_new(wmem_file_scope(), tcpcl_transfer_t)((tcpcl_transfer_t*)wmem_alloc((wmem_file_scope()), sizeof(tcpcl_transfer_t
)))
;
809 obj->seg_list = wmem_list_new(wmem_file_scope());
810 obj->ack_list = wmem_list_new(wmem_file_scope());
811 obj->total_length = NULL((void*)0);
812 return obj;
813}
814
815static tcpcl_transfer_t * get_or_create_transfer_t(wmem_map_t *table, const uint64_t xfer_id) {
816 tcpcl_transfer_t *xfer = wmem_map_lookup(table, &xfer_id);
817 if (!xfer) {
818 uint64_t *key = wmem_new(wmem_file_scope(), uint64_t)((uint64_t*)wmem_alloc((wmem_file_scope()), sizeof(uint64_t))
)
;
819 *key = xfer_id;
820 xfer = tcpcl_transfer_new();
821 wmem_map_insert(table, key, xfer);
822 }
823 return xfer;
824}
825
826static tcpcl_peer_t * tcpcl_peer_new(void) {
827 tcpcl_peer_t *obj = wmem_new0(wmem_file_scope(), tcpcl_peer_t)((tcpcl_peer_t*)wmem_alloc0((wmem_file_scope()), sizeof(tcpcl_peer_t
)))
;
828 clear_address(&(obj->addr));
829 obj->frame_loc_to_transfer = wmem_map_new(wmem_file_scope(), tcpcl_frame_loc_hash, tcpcl_frame_loc_equal);
830 obj->transfers = wmem_map_new(wmem_file_scope(), g_int64_hash, g_int64_equal);
831 return obj;
832}
833
834static void tcpcl_peer_associate_transfer(tcpcl_peer_t *peer, const tcpcl_frame_loc_t *loc, const uint64_t xfer_id) {
835 void * *xfer = wmem_map_lookup(peer->frame_loc_to_transfer, loc);
836 if (!xfer) {
837 tcpcl_frame_loc_t *key = tcpcl_frame_loc_clone(wmem_file_scope(), loc);
838 uint64_t *val = wmem_new(wmem_file_scope(), uint64_t)((uint64_t*)wmem_alloc((wmem_file_scope()), sizeof(uint64_t))
)
;
839 *val = xfer_id;
840 wmem_map_insert(peer->frame_loc_to_transfer, key, val);
841 }
842}
843
844static tcpcl_conversation_t * tcpcl_conversation_new(void) {
845 tcpcl_conversation_t *obj = wmem_new0(wmem_file_scope(), tcpcl_conversation_t)((tcpcl_conversation_t*)wmem_alloc0((wmem_file_scope()), sizeof
(tcpcl_conversation_t)))
;
846 obj->active = tcpcl_peer_new();
847 obj->passive = tcpcl_peer_new();
848 return obj;
849}
850
851tcpcl_dissect_ctx_t * tcpcl_dissect_ctx_get(tvbuff_t *tvb, packet_info *pinfo, const int offset) {
852 conversation_t *convo = find_or_create_conversation(pinfo);
853 tcpcl_conversation_t *tcpcl_convo = (tcpcl_conversation_t *)conversation_get_proto_data(convo, proto_tcpcl);
854 if (!tcpcl_convo) {
855 return NULL((void*)0);
856 }
857
858 tcpcl_dissect_ctx_t *ctx = wmem_new0(pinfo->pool, tcpcl_dissect_ctx_t)((tcpcl_dissect_ctx_t*)wmem_alloc0((pinfo->pool), sizeof(tcpcl_dissect_ctx_t
)))
;
859 ctx->convo = tcpcl_convo;
860 ctx->cur_loc = tcpcl_frame_loc_new(pinfo->pool, pinfo, tvb, offset);
861
862 const bool_Bool src_is_active = (
863 addresses_equal(&(ctx->convo->active->addr), &(pinfo->src))
864 && (ctx->convo->active->port == pinfo->srcport)
865 );
866 if (src_is_active) {
867 ctx->tx_peer = ctx->convo->active;
868 ctx->rx_peer = ctx->convo->passive;
869 }
870 else {
871 ctx->tx_peer = ctx->convo->passive;
872 ctx->rx_peer = ctx->convo->active;
873 }
874
875 ctx->is_contact = (
876 !(ctx->tx_peer->chdr_missing)
877 && (
878 !(ctx->tx_peer->chdr_seen)
879 || tcpcl_frame_loc_equal(ctx->tx_peer->chdr_seen, ctx->cur_loc)
880 )
881 );
882
883 return ctx;
884}
885
886static void set_chdr_missing(tcpcl_peer_t *peer, uint8_t version) {
887 peer->chdr_missing = true1;
888 peer->version = version;
889 // assumed parameters
890 peer->segment_mru = UINT64_MAX(18446744073709551615UL);
891 peer->transfer_mru = UINT64_MAX(18446744073709551615UL);
892}
893
894
895static void try_negotiate(tcpcl_dissect_ctx_t *ctx, packet_info *pinfo) {
896 if (!(ctx->convo->contact_negotiated)
897 && (ctx->convo->active->chdr_seen)
898 && (ctx->convo->passive->chdr_seen)) {
899 ctx->convo->session_use_tls = (
900 ctx->convo->active->can_tls & ctx->convo->passive->can_tls
901 );
902 ctx->convo->contact_negotiated = true1;
903
904 if (ctx->convo->session_use_tls
905 && (!(ctx->convo->session_tls_start))) {
906 col_append_str(pinfo->cinfo, COL_INFO, " [STARTTLS]");
907 ctx->convo->session_tls_start = tcpcl_frame_loc_clone(wmem_file_scope(), ctx->cur_loc);
908 ssl_starttls_ack(tls_handle, pinfo, tcpcl_handle);
909 }
910 }
911
912 if (!(ctx->convo->sess_negotiated)
913 && (ctx->convo->active->sess_init_seen)
914 && (ctx->convo->passive->sess_init_seen)) {
915 ctx->convo->sess_keepalive = MIN((((ctx->convo->active->keepalive) < (ctx->convo
->passive->keepalive)) ? (ctx->convo->active->
keepalive) : (ctx->convo->passive->keepalive))
916 ctx->convo->active->keepalive,(((ctx->convo->active->keepalive) < (ctx->convo
->passive->keepalive)) ? (ctx->convo->active->
keepalive) : (ctx->convo->passive->keepalive))
917 ctx->convo->passive->keepalive(((ctx->convo->active->keepalive) < (ctx->convo
->passive->keepalive)) ? (ctx->convo->active->
keepalive) : (ctx->convo->passive->keepalive))
918 )(((ctx->convo->active->keepalive) < (ctx->convo
->passive->keepalive)) ? (ctx->convo->active->
keepalive) : (ctx->convo->passive->keepalive))
;
919 ctx->convo->sess_negotiated = true1;
920
921 }
922}
923
924typedef struct {
925 // key type for addresses_ports_reassembly_table_functions
926 void *addr_port;
927 // TCPCL ID
928 uint64_t xfer_id;
929} tcpcl_fragment_key_t;
930
931static unsigned fragment_key_hash(const void *ptr) {
932 const tcpcl_fragment_key_t *obj = (const tcpcl_fragment_key_t *)ptr;
933 return (
934 addresses_ports_reassembly_table_functions.hash_func(obj->addr_port)
935 ^ g_int64_hash(&(obj->xfer_id))
936 );
937}
938
939static gboolean fragment_key_equal(const void *ptrA, const void *ptrB) {
940 const tcpcl_fragment_key_t *objA = (const tcpcl_fragment_key_t *)ptrA;
941 const tcpcl_fragment_key_t *objB = (const tcpcl_fragment_key_t *)ptrB;
942 return (
943 addresses_ports_reassembly_table_functions.equal_func(objA->addr_port, objB->addr_port)
944 && (objA->xfer_id == objB->xfer_id)
945 );
946}
947
948static void *fragment_key_temporary(const packet_info *pinfo, const uint32_t id, const void *data) {
949 tcpcl_fragment_key_t *obj = g_slice_new(tcpcl_fragment_key_t)((tcpcl_fragment_key_t*) g_slice_alloc ((sizeof (tcpcl_fragment_key_t
) > 0 ? sizeof (tcpcl_fragment_key_t) : 1)))
;
950 obj->addr_port = addresses_ports_reassembly_table_functions.temporary_key_func(pinfo, id, NULL((void*)0));
951 obj->xfer_id = *((const uint64_t *)data);
952 return (void *)obj;
953}
954
955static void *fragment_key_persistent(const packet_info *pinfo, const uint32_t id, const void *data) {
956 tcpcl_fragment_key_t *obj = g_slice_new(tcpcl_fragment_key_t)((tcpcl_fragment_key_t*) g_slice_alloc ((sizeof (tcpcl_fragment_key_t
) > 0 ? sizeof (tcpcl_fragment_key_t) : 1)))
;
957 obj->addr_port = addresses_ports_reassembly_table_functions.persistent_key_func(pinfo, id, NULL((void*)0));
958 obj->xfer_id = *((const uint64_t *)data);
959 return (void *)obj;
960}
961
962static void fragment_key_free_temporary(void *ptr) {
963 tcpcl_fragment_key_t *obj = (tcpcl_fragment_key_t *)ptr;
964 if (obj) {
965 addresses_ports_reassembly_table_functions.free_temporary_key_func(obj->addr_port);
966 g_slice_free(tcpcl_fragment_key_t, obj)do { if (1) g_slice_free1 (sizeof (tcpcl_fragment_key_t), (obj
)); else (void) ((tcpcl_fragment_key_t*) 0 == (obj)); } while
(0)
;
967 }
968}
969
970static void fragment_key_free_persistent(void *ptr) {
971 tcpcl_fragment_key_t *obj = (tcpcl_fragment_key_t *)ptr;
972 if (obj) {
973 addresses_ports_reassembly_table_functions.free_persistent_key_func(obj->addr_port);
974 g_slice_free(tcpcl_fragment_key_t, obj)do { if (1) g_slice_free1 (sizeof (tcpcl_fragment_key_t), (obj
)); else (void) ((tcpcl_fragment_key_t*) 0 == (obj)); } while
(0)
;
975 }
976}
977
978static reassembly_table_functions xfer_reassembly_table_functions = {
979 fragment_key_hash,
980 fragment_key_equal,
981 fragment_key_temporary,
982 fragment_key_persistent,
983 fragment_key_free_temporary,
984 fragment_key_free_persistent
985};
986
987/** Record metadata about one segment in a transfer.
988 */
989static void transfer_add_segment(tcpcl_dissect_ctx_t *ctx, uint64_t xfer_id, uint8_t flags,
990 uint64_t data_len,
991 packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree_msg,
992 proto_item *item_msg, proto_item *item_flags) {
993 tcpcl_transfer_t *xfer = get_or_create_transfer_t(ctx->tx_peer->transfers, xfer_id);
994
995 uint8_t flag_start, flag_end;
996 if (ctx->tx_peer->version == 3) {
997 flag_start = TCPCLV3_DATA_START_FLAG;
998 flag_end = TCPCLV3_DATA_END_FLAG;
999 }
1000 else {
1001 flag_start = TCPCLV4_TRANSFER_FLAG_START;
1002 flag_end = TCPCLV4_TRANSFER_FLAG_END;
1003 }
1004
1005 // Add or get the segment metadata
1006 tcpcl_seg_meta_t *seg_meta = tcpcl_seg_meta_new(pinfo, ctx->cur_loc);
1007 wmem_list_frame_t *frm = wmem_list_find_custom(xfer->seg_list, seg_meta, tcpcl_seg_meta_compare_loc);
1008 if (frm) {
1009 tcpcl_seg_meta_free(seg_meta);
1010 seg_meta = wmem_list_frame_data(frm);
1011 }
1012 else {
1013 wmem_list_append(xfer->seg_list, seg_meta);
1014 frm = wmem_list_tail(xfer->seg_list);
1015 // Set for new item
1016 seg_meta->flags = flags;
1017 }
1018
1019 // mark start-of-transfer
1020 if (!(seg_meta->related_start)) {
1021 wmem_list_frame_t *frm_front = wmem_list_head(xfer->seg_list);
1022 tcpcl_seg_meta_t *seg_front = frm_front ? wmem_list_frame_data(frm_front) : NULL((void*)0);
1023 if (seg_front && (seg_front->flags & flag_start)) {
1024 seg_meta->related_start = seg_front;
1025 }
1026 }
1027
1028 // accumulate segment sizes
1029 uint64_t prev_seen_len;
1030 wmem_list_frame_t *frm_prev = wmem_list_frame_prev(frm);
1031 if (!frm_prev) {
1032 if (!(flags & flag_start)) {
1033 expert_add_info(pinfo, item_flags, &ei_tcpclv4_xfer_seg_missing_start);
1034 }
1035 prev_seen_len = 0;
1036 }
1037 else {
1038 const tcpcl_seg_meta_t *seg_prev = wmem_list_frame_data(frm_prev);
1039 if (flags & flag_start) {
1040 expert_add_info(pinfo, item_flags, &ei_tcpclv4_xfer_seg_duplicate_start);
1041 }
1042 prev_seen_len = seg_prev->seen_len;
1043 }
1044 wmem_list_frame_t *frm_next = wmem_list_frame_next(frm);
1045 if (!frm_next) {
1046 if (!(flags & flag_end)) {
1047 expert_add_info(pinfo, item_flags, &ei_tcpclv4_xfer_seg_missing_end);
1048 }
1049 }
1050 else {
1051 if (flags & flag_end) {
1052 expert_add_info(pinfo, item_flags, &ei_tcpclv4_xfer_seg_duplicate_end);
1053 }
1054 }
1055 seg_meta->seen_len = prev_seen_len + data_len;
1056
1057 proto_item *item_seen = proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_segment_seen_len, tvb, 0, 0, seg_meta->seen_len);
1058 proto_item_set_generated(item_seen);
1059 if (seg_meta->seen_len > ctx->rx_peer->transfer_mru) {
1060 expert_add_info(pinfo, item_seen, &ei_tcpclv4_xferload_over_xfer_mru);
1061 }
1062 if (xfer->total_length) {
1063 if (seg_meta->seen_len > *(xfer->total_length)) {
1064 expert_add_info(pinfo, item_seen, &ei_xfer_seg_over_total_len);
1065 }
1066 else if ((flags & flag_end)
1067 && (seg_meta->seen_len != *(xfer->total_length))) {
1068 expert_add_info(pinfo, item_seen, &ei_xfer_mismatch_total_len);
1069 }
1070 proto_item *item_total = proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_total_len, tvb, 0, 0, *(xfer->total_length));
1071 proto_item_set_generated(item_total);
1072 }
1073
1074 if (seg_meta->related_ack) {
1075 proto_item *item_rel = proto_tree_add_uint(tree_msg, hf_tcpclv4_xfer_segment_related_ack, tvb, 0, 0, seg_meta->related_ack->frame_loc.frame_num);
1076 proto_item_set_generated(item_rel);
1077
1078 nstime_t td;
1079 nstime_delta(&td, &(seg_meta->related_ack->frame_time), &(seg_meta->frame_time));
1080 proto_item *item_td = proto_tree_add_time(tree_msg, hf_tcpclv4_xfer_segment_time_diff, tvb, 0, 0, &td);
1081 proto_item_set_generated(item_td);
1082
1083 }
1084 else {
1085 expert_add_info(pinfo, item_msg, &ei_tcpclv4_xfer_seg_no_relation);
1086 }
1087 if (seg_meta->related_start && (seg_meta->related_start != seg_meta)) {
1088 proto_item *item_rel = proto_tree_add_uint(tree_msg, hf_tcpclv4_xfer_segment_related_start, tvb, 0, 0, seg_meta->related_start->frame_loc.frame_num);
1089 proto_item_set_generated(item_rel);
1090
1091 nstime_t td;
1092 nstime_delta(&td, &(seg_meta->frame_time), &(seg_meta->related_start->frame_time));
1093 proto_item *item_td = proto_tree_add_time(tree_msg, hf_tcpclv4_xfer_segment_time_start, tvb, 0, 0, &td);
1094 proto_item_set_generated(item_td);
1095 }
1096}
1097
1098static void transfer_add_ack(tcpcl_dissect_ctx_t *ctx, uint64_t xfer_id, uint8_t flags,
1099 uint64_t ack_len,
1100 packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree_msg,
1101 proto_item *item_msg, proto_item *item_flags) {
1102 tcpcl_transfer_t *xfer = get_or_create_transfer_t(ctx->rx_peer->transfers, xfer_id);
1103
1104 // Add or get the ack metadata
1105 tcpcl_ack_meta_t *ack_meta = tcpcl_ack_meta_new(pinfo, ctx->cur_loc);
1106 wmem_list_frame_t *frm = wmem_list_find_custom(xfer->ack_list, ack_meta, tcpcl_ack_meta_compare_loc);
1107 if (frm) {
1108 tcpcl_ack_meta_free(ack_meta);
1109 ack_meta = wmem_list_frame_data(frm);
1110 }
1111 else {
1112 wmem_list_append(xfer->ack_list, ack_meta);
1113 // Set for new item
1114 ack_meta->flags = flags;
1115 ack_meta->seen_len = ack_len;
1116 }
1117
1118 // mark start-of-transfer
1119 if (!(ack_meta->related_start)) {
1120 wmem_list_frame_t *frm_front = wmem_list_head(xfer->seg_list);
1121 tcpcl_seg_meta_t *seg_front = frm_front ? wmem_list_frame_data(frm_front) : NULL((void*)0);
1122 if (seg_front && (seg_front->flags & TCPCLV4_TRANSFER_FLAG_START)) {
1123 ack_meta->related_start = seg_front;
1124 }
1125 }
1126
1127 // Assemble both of the links here, as ACK will always follow segment
1128 if (!(ack_meta->related_seg)) {
1129 wmem_list_frame_t *seg_iter = wmem_list_head(xfer->seg_list);
1130 for (; seg_iter; seg_iter = wmem_list_frame_next(seg_iter)) {
1131 tcpcl_seg_meta_t *seg_meta = wmem_list_frame_data(seg_iter);
1132 if (seg_meta->seen_len == ack_meta->seen_len) {
1133 seg_meta->related_ack = ack_meta;
1134 ack_meta->related_seg = seg_meta;
1135 }
1136 }
1137 }
1138
1139 if (xfer->total_length) {
1140 proto_item *item_total = proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_total_len, tvb, 0, 0, *(xfer->total_length));
1141 proto_item_set_generated(item_total);
1142 }
1143 if (ack_meta->related_seg) {
1144 proto_item *item_rel = proto_tree_add_uint(tree_msg, hf_tcpclv4_xfer_ack_related_seg, tvb, 0, 0, ack_meta->related_seg->frame_loc.frame_num);
1145 proto_item_set_generated(item_rel);
1146
1147 nstime_t td;
1148 nstime_delta(&td, &(ack_meta->frame_time), &(ack_meta->related_seg->frame_time));
1149 proto_item *item_td = proto_tree_add_time(tree_msg, hf_tcpclv4_xfer_ack_time_diff, tvb, 0, 0, &td);
1150 proto_item_set_generated(item_td);
1151
1152 if (item_flags && (ack_meta->flags != ack_meta->related_seg->flags)) {
1153 expert_add_info(pinfo, item_flags, &ei_xfer_ack_mismatch_flags);
1154 }
1155 }
1156 else {
1157 expert_add_info(pinfo, item_msg, &ei_xfer_ack_no_relation);
1158 }
1159 if (ack_meta->related_start) {
1160 proto_item *item_rel = proto_tree_add_uint(tree_msg, hf_tcpclv4_xfer_ack_related_start, tvb, 0, 0, ack_meta->related_start->frame_loc.frame_num);
1161 proto_item_set_generated(item_rel);
1162
1163 nstime_t td;
1164 nstime_delta(&td, &(ack_meta->frame_time), &(ack_meta->related_start->frame_time));
1165 proto_item *item_td = proto_tree_add_time(tree_msg, hf_tcpclv4_xfer_ack_time_start, tvb, 0, 0, &td);
1166 proto_item_set_generated(item_td);
1167 }
1168}
1169
1170static void transfer_add_refuse(tcpcl_dissect_ctx_t *ctx, uint64_t xfer_id,
1171 packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree_msg,
1172 proto_item *item_msg) {
1173 const tcpcl_transfer_t *xfer = wmem_map_lookup(ctx->rx_peer->transfers, &xfer_id);
1174 const tcpcl_seg_meta_t *seg_last = NULL((void*)0);
1175 if (xfer) {
1176 wmem_list_frame_t *seg_iter = wmem_list_tail(xfer->seg_list);
1177 seg_iter = seg_iter ? wmem_list_frame_prev(seg_iter) : NULL((void*)0);
1178 seg_last = seg_iter ? wmem_list_frame_data(seg_iter) : NULL((void*)0);
1179 }
1180
1181 if (seg_last) {
1182 proto_item *item_rel = proto_tree_add_uint(tree_msg, hf_tcpclv4_xfer_refuse_related_seg, tvb, 0, 0, seg_last->frame_loc.frame_num);
1183 proto_item_set_generated(item_rel);
1184 }
1185 else {
1186 expert_add_info(pinfo, item_msg, &ei_tcpclv4_xfer_refuse_no_transfer);
1187 }
1188}
1189
1190static int get_clamped_length(uint64_t orig, packet_info *pinfo, proto_item *item) {
1191 int clamped;
1192 if (orig > INT_MAX2147483647) {
1193 clamped = INT_MAX2147483647;
1194 if (pinfo && item) {
1195 expert_add_info(pinfo, item, &ei_length_clamped);
1196 }
1197 }
1198 else {
1199 clamped = (int) orig;
1200 }
1201 return clamped;
1202}
1203
1204static unsigned
1205get_v3_msg_len(packet_info *pinfo _U___attribute__((unused)), tvbuff_t *tvb, int offset,
1206 tcpcl_dissect_ctx_t *ctx _U___attribute__((unused)))
1207{
1208 uint64_t len;
1209 unsigned bytecount;
1210 uint8_t conv_hdr = tvb_get_uint8(tvb, offset);
1211 offset += 1;
1212 unsigned msg_len = 1;
1213
1214 switch (conv_hdr & TCPCLV3_TYPE_MASK)
1215 {
1216 case TCPCLV3_DATA_SEGMENT: {
1217 /* get length from sdnv */
1218 bytecount = tvb_get_sdnv(tvb, offset, &len);
1219 if (bytecount == 0) {
1220 return 0;
1221 }
1222 const int len_clamp = get_clamped_length(len, NULL((void*)0), NULL((void*)0));
1223 msg_len += bytecount + (unsigned)len_clamp;
1224 break;
1225 }
1226 case TCPCLV3_ACK_SEGMENT:
1227 /* get length from sdnv */
1228 bytecount = tvb_get_sdnv(tvb, offset, &len);
1229 if (bytecount == 0) {
1230 return 0;
1231 }
1232 msg_len += bytecount;
1233 break;
1234
1235 case TCPCLV3_KEEP_ALIVE:
1236 case TCPCLV3_REFUSE_BUNDLE:
1237 /* always 1 byte */
1238 break;
1239 case TCPCLV3_SHUTDOWN:
1240 if (conv_hdr & TCPCLV3_SHUTDOWN_REASON) {
1241 msg_len += 1;
1242 }
1243 if (conv_hdr & TCPCLV3_SHUTDOWN_DELAY) {
1244 msg_len += 2;
1245 }
1246 break;
1247
1248 case TCPCLV3_LENGTH:
1249 /* get length from sdnv */
1250 bytecount = tvb_get_sdnv(tvb, offset, &len);
1251 if (bytecount == 0) {
1252 return 0;
1253 }
1254 msg_len += bytecount;
1255 break;
1256
1257 default:
1258 // no known message
1259 return 0;
1260 }
1261
1262 return msg_len;
1263}
1264
1265static int
1266dissect_v3_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1267 tcpcl_dissect_ctx_t *ctx)
1268{
1269 uint8_t conv_hdr;
1270 const char *msgtype_name;
1271 uint8_t refuse_bundle_hdr;
1272 int offset = 0;
1273 unsigned sdnv_length;
1274 uint64_t segment_length;
1275 proto_item *conv_item, *sub_item;
1276 proto_tree *conv_tree, *sub_tree;
1277 uint64_t *xfer_id = NULL((void*)0);
1278 proto_item *item_xfer_id = NULL((void*)0);
1279
1280 conv_item = proto_tree_add_item(tree, hf_tcpclv3_mhdr, tvb, 0, -1, ENC_NA0x00000000);
1281 conv_tree = proto_item_add_subtree(conv_item, ett_tcpclv3_mhdr);
1282
1283 conv_hdr = tvb_get_uint8(tvb, offset);
1284 proto_tree_add_item(conv_tree, hf_tcpclv3_pkt_type, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
1285
1286 msgtype_name = val_to_str_const((conv_hdr>>4)&0xF, v3_message_type_vals, "Unknown");
1287 col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), msgtype_name);
1288 proto_item_append_text(proto_tree_get_parent(conv_tree), ": %s", msgtype_name);
1289
1290 switch (conv_hdr & TCPCLV3_TYPE_MASK) {
1291 case TCPCLV3_DATA_SEGMENT: {
1292 proto_item *item_flags;
1293
1294 item_flags = proto_tree_add_bitmask(
1295 conv_tree, tvb,
1296 offset, hf_tcpclv3_data_procflags,
1297 ett_tcpclv3_data_procflags, v3_data_procflags,
1298 ENC_BIG_ENDIAN0x00000000
1299 );
1300 offset += 1;
1301
1302 /* Only Start and End flags (bits 0 & 1) are valid in Data Segment */
1303 if ((conv_hdr & ~((uint8_t)TCPCLV3_TYPE_MASK | (uint8_t)TCPCLV3_DATA_FLAGS)) != 0) {
1304 expert_add_info(pinfo, item_flags, &ei_tcpclv3_data_flags);
1305 }
1306
1307 sub_item = proto_tree_add_item_ret_varint(conv_tree, hf_tcpclv3_data_segment_length, tvb, offset, -1, ENC_VARINT_SDNV0x00000010, &segment_length, &sdnv_length);
1308 offset += sdnv_length;
1309 const int data_len_clamp = get_clamped_length(segment_length, pinfo, sub_item);
1310
1311 // implied transfer ID
1312 xfer_id = wmem_map_lookup(ctx->tx_peer->frame_loc_to_transfer, ctx->cur_loc);
1313 if (!xfer_id) {
1314 xfer_id = wmem_new(pinfo->pool, uint64_t)((uint64_t*)wmem_alloc((pinfo->pool), sizeof(uint64_t)));
1315 *xfer_id = wmem_map_size(ctx->tx_peer->transfers);
1316
1317 if (conv_hdr & TCPCLV3_DATA_START_FLAG) {
1318 *xfer_id += 1;
1319 get_or_create_transfer_t(ctx->tx_peer->transfers, *xfer_id);
1320 }
1321 tcpcl_peer_associate_transfer(ctx->tx_peer, ctx->cur_loc, *xfer_id);
1322 }
1323 item_xfer_id = proto_tree_add_uint64(conv_tree, hf_tcpclv3_xfer_id, tvb, 0, 0, *xfer_id);
1324 proto_item_set_generated(item_xfer_id);
1325
1326 proto_tree_add_item(conv_tree, hf_tcpclv3_data_segment_data, tvb, offset, data_len_clamp, ENC_NA0x00000000);
1327
1328 if (tcpcl_analyze_sequence) {
1329 transfer_add_segment(ctx, *xfer_id, (conv_hdr & TCPCLV3_DATA_FLAGS), segment_length, pinfo, tvb, conv_tree, conv_item, item_flags);
1330 }
1331
1332 if (tcpcl_desegment_transfer) {
1333 // Reassemble the segments
1334 fragment_head *frag_msg;
1335 frag_msg = fragment_add_seq_next(
1336 &xfer_reassembly_table,
1337 tvb, offset,
1338 pinfo, 0, xfer_id,
1339 data_len_clamp,
1340 !(conv_hdr & TCPCLV3_DATA_END_FLAG)
1341 );
1342 ctx->xferload = process_reassembled_data(
1343 tvb, offset, pinfo,
1344 "Reassembled Transfer",
1345 frag_msg,
1346 &xfer_frag_items,
1347 NULL((void*)0),
1348 tree
1349 );
1350 }
1351 offset += data_len_clamp;
1352
1353 break;
1354 }
1355 case TCPCLV3_ACK_SEGMENT: {
1356 /*No valid flags*/
1357 offset += 1;
1358
1359 sub_item = proto_tree_add_item_ret_varint(conv_tree, hf_tcpclv3_ack_length, tvb, offset, -1, ENC_VARINT_SDNV0x00000010, &segment_length, &sdnv_length);
Value stored to 'sub_item' is never read
1360 offset += sdnv_length;
1361
1362 // implied transfer ID
1363 xfer_id = wmem_map_lookup(ctx->rx_peer->frame_loc_to_transfer, ctx->cur_loc);
1364 if (!xfer_id) {
1365 xfer_id = wmem_new(pinfo->pool, uint64_t)((uint64_t*)wmem_alloc((pinfo->pool), sizeof(uint64_t)));
1366 *xfer_id = wmem_map_size(ctx->rx_peer->transfers);
1367
1368 tcpcl_peer_associate_transfer(ctx->rx_peer, ctx->cur_loc, *xfer_id);
1369 }
1370 item_xfer_id = proto_tree_add_uint64(conv_tree, hf_tcpclv3_xfer_id, tvb, 0, 0, *xfer_id);
1371 proto_item_set_generated(item_xfer_id);
1372
1373 if (tcpcl_analyze_sequence) {
1374 transfer_add_ack(ctx, *xfer_id, 0, segment_length, pinfo, tvb, conv_tree, conv_item, NULL((void*)0));
1375 }
1376
1377 break;
1378 }
1379 case TCPCLV3_KEEP_ALIVE:
1380 /*No valid flags in Keep Alive*/
1381 offset += 1;
1382 break;
1383
1384 case TCPCLV3_SHUTDOWN:
1385 /* Add tree for Shutdown Flags */
1386 sub_item = proto_tree_add_item(conv_tree, hf_tcpclv3_shutdown_flags, tvb,
1387 offset, 1, ENC_BIG_ENDIAN0x00000000);
1388 sub_tree = proto_item_add_subtree(sub_item, ett_tcpclv3_shutdown_flags);
1389
1390 proto_tree_add_item(sub_tree, hf_tcpclv3_shutdown_flags_reason,
1391 tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
1392 proto_tree_add_item(sub_tree, hf_tcpclv3_shutdown_flags_delay,
1393 tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
1394
1395 offset += 1;
1396 if (conv_hdr & TCPCLV3_SHUTDOWN_REASON) {
1397 proto_tree_add_item(conv_tree,
1398 hf_tcpclv3_shutdown_reason, tvb,
1399 offset, 1, ENC_BIG_ENDIAN0x00000000);
1400 offset += 1;
1401 }
1402 if (conv_hdr & TCPCLV3_SHUTDOWN_DELAY) {
1403 proto_tree_add_item(conv_tree,
1404 hf_tcpclv3_shutdown_delay, tvb,
1405 offset, 2, ENC_BIG_ENDIAN0x00000000);
1406 offset += 1;
1407 }
1408 break;
1409 case TCPCLV3_REFUSE_BUNDLE:
1410 /*No valid flags*/
1411 offset += 1;
1412
1413 refuse_bundle_hdr = tvb_get_uint8(tvb, offset);
1414 proto_tree_add_item(conv_tree, hf_tcpclv3_refuse_reason_code, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
1415 offset += 1;
1416 col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const((refuse_bundle_hdr>>4)&0xF, v3_refuse_reason_code, "Unknown"));
1417
1418 // implied transfer ID
1419 xfer_id = wmem_map_lookup(ctx->rx_peer->frame_loc_to_transfer, ctx->cur_loc);
1420 if (!xfer_id) {
1421 xfer_id = wmem_new(pinfo->pool, uint64_t)((uint64_t*)wmem_alloc((pinfo->pool), sizeof(uint64_t)));
1422 *xfer_id = wmem_map_size(ctx->rx_peer->transfers);
1423
1424 tcpcl_peer_associate_transfer(ctx->rx_peer, ctx->cur_loc, *xfer_id);
1425 }
1426 item_xfer_id = proto_tree_add_uint64(conv_tree, hf_tcpclv3_xfer_id, tvb, 0, 0, *xfer_id);
1427 proto_item_set_generated(item_xfer_id);
1428
1429 if (tcpcl_analyze_sequence) {
1430 transfer_add_refuse(ctx, *xfer_id, pinfo, tvb, conv_tree, conv_item);
1431 }
1432
1433 break;
1434
1435 default:
1436 expert_add_info(pinfo, proto_tree_get_parent(conv_tree), &ei_tcpclv3_invalid_msg_type);
1437 break;
1438 }
1439
1440 return offset;
1441}
1442
1443static unsigned get_v4_msg_len(packet_info *pinfo _U___attribute__((unused)), tvbuff_t *tvb, int offset,
1444 tcpcl_dissect_ctx_t *ctx _U___attribute__((unused))) {
1445 const int init_offset = offset;
1446 uint8_t msgtype = tvb_get_uint8(tvb, offset);
1447 offset += 1;
1448 switch(msgtype) {
1449 case TCPCLV4_MSGTYPE_SESS_INIT: {
1450 if (tvb_reported_length_remaining(tvb, offset) < 2 + 8 + 8 + 2) {
1451 return 0;
1452 }
1453 offset += 2 + 8 + 8;
1454 uint16_t nodeid_len = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1455 offset += 2;
1456 if (tvb_reported_length_remaining(tvb, offset) < nodeid_len + 4U) {
1457 return 0;
1458 }
1459 offset += nodeid_len;
1460 uint32_t extlist_len = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1461 offset += 4;
1462 if (ckd_add(&offset, offset, extlist_len)__builtin_add_overflow((offset), (extlist_len), (&offset)
)
) {
1463 THROW(ReportedBoundsError)except_throw(1, (3), ((void*)0));
1464 }
1465 break;
1466 }
1467 case TCPCLV4_MSGTYPE_SESS_TERM: {
1468 offset += 1 + 1;
1469 break;
1470 }
1471 case TCPCLV4_MSGTYPE_XFER_SEGMENT: {
1472 if (tvb_reported_length_remaining(tvb, offset) < 1) {
1473 return 0;
1474 }
1475 uint8_t flags = tvb_get_uint8(tvb, offset);
1476 offset += 1;
1477 offset += 8;
1478 if (flags & TCPCLV4_TRANSFER_FLAG_START) {
1479 if (tvb_reported_length_remaining(tvb, offset) < 4) {
1480 return 0;
1481 }
1482 uint32_t extlist_len = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1483 offset += 4;
1484 if ((unsigned)tvb_reported_length_remaining(tvb, offset) < extlist_len) {
1485 return 0;
1486 }
1487 offset += extlist_len;
1488 }
1489 if (tvb_reported_length_remaining(tvb, offset) < 8) {
1490 return 0;
1491 }
1492 uint64_t data_len = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1493 offset += 8;
1494 const int data_len_clamp = get_clamped_length(data_len, NULL((void*)0), NULL((void*)0));
1495 if (ckd_add(&offset, offset, data_len_clamp)__builtin_add_overflow((offset), (data_len_clamp), (&offset
))
) {
1496 THROW(ReportedBoundsError)except_throw(1, (3), ((void*)0));
1497 }
1498 break;
1499 }
1500 case TCPCLV4_MSGTYPE_XFER_ACK: {
1501 offset += 1 + 8 + 8;
1502 break;
1503 }
1504 case TCPCLV4_MSGTYPE_XFER_REFUSE: {
1505 offset += 1 + 8;
1506 break;
1507 }
1508 case TCPCLV4_MSGTYPE_KEEPALIVE: {
1509 break;
1510 }
1511 case TCPCLV4_MSGTYPE_MSG_REJECT: {
1512 offset += 1 + 1;
1513 break;
1514 }
1515 default:
1516 // no known message
1517 return 0;
1518 }
1519 return offset - init_offset;
1520}
1521
1522static int
1523dissect_v4_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1524 tcpcl_dissect_ctx_t *ctx _U___attribute__((unused))) {
1525 int offset = 0;
1526 // Length of non-protocol 'payload' data in this message
1527 int payload_len = 0;
1528
1529 uint8_t msgtype = 0;
1530 const char *msgtype_name = NULL((void*)0);
1531
1532 proto_item *item_msg = proto_tree_add_item(tree, hf_tcpclv4_mhdr_tree, tvb, offset, 0, ENC_NA0x00000000);
1533 proto_tree *tree_msg = proto_item_add_subtree(item_msg, ett_tcpclv4_mhdr);
1534
1535 msgtype = tvb_get_uint8(tvb, offset);
1536 proto_tree_add_uint(tree_msg, hf_tcpclv4_mhdr_type, tvb, offset, 1, msgtype);
1537 offset += 1;
1538 msgtype_name = val_to_str(pinfo->pool, msgtype, v4_message_type_vals, "type 0x%02" PRIx32"x");
1539 wmem_strbuf_t *suffix_text = wmem_strbuf_new(pinfo->pool, NULL((void*)0));
1540
1541 switch(msgtype) {
1542 case TCPCLV4_MSGTYPE_SESS_INIT: {
1543 uint16_t keepalive = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1544 proto_tree_add_uint(tree_msg, hf_tcpclv4_sess_init_keepalive, tvb, offset, 2, keepalive);
1545 offset += 2;
1546
1547 uint64_t seg_mru = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1548 proto_tree_add_uint64(tree_msg, hf_tcpclv4_sess_init_seg_mru, tvb, offset, 8, seg_mru);
1549 offset += 8;
1550
1551 uint64_t xfer_mru = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1552 proto_tree_add_uint64(tree_msg, hf_tcpclv4_sess_init_xfer_mru, tvb, offset, 8, xfer_mru);
1553 offset += 8;
1554
1555 uint16_t nodeid_len = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1556 proto_tree_add_uint(tree_msg, hf_tcpclv4_sess_init_nodeid_len, tvb, offset, 2, nodeid_len);
1557 offset += 2;
1558
1559 {
1560 uint8_t *nodeid_data = tvb_get_string_enc(pinfo->pool, tvb, offset, nodeid_len, ENC_UTF_80x00000002);
1561 proto_tree_add_string(tree_msg, hf_tcpclv4_sess_init_nodeid_data, tvb, offset, nodeid_len, (const char *)nodeid_data);
1562 }
1563 offset += nodeid_len;
1564
1565 uint32_t extlist_len = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1566 proto_tree_add_uint(tree_msg, hf_tcpclv4_sess_init_extlist_len, tvb, offset, 4, extlist_len);
1567 offset += 4;
1568
1569 int extlist_offset = 0;
1570 while (extlist_offset < (int)extlist_len) {
1571 int extitem_offset = 0;
1572 proto_item *item_ext = proto_tree_add_item(tree_msg, hf_tcpclv4_sessext_tree, tvb, offset + extlist_offset, 0, ENC_NA0x00000000);
1573 proto_tree *tree_ext = proto_item_add_subtree(item_ext, ett_tcpclv4_sessext);
1574
1575 uint8_t extitem_flags = tvb_get_uint8(tvb, offset + extlist_offset + extitem_offset);
1576 proto_tree_add_bitmask(tree_ext, tvb, offset + extlist_offset + extitem_offset, hf_tcpclv4_sessext_flags, ett_tcpclv4_sessext_flags, v4_sessext_flags, ENC_BIG_ENDIAN0x00000000);
1577 extitem_offset += 1;
1578 const bool_Bool is_critical = (extitem_flags & TCPCLV4_EXTENSION_FLAG_CRITICAL);
1579 if (is_critical) {
1580 expert_add_info(pinfo, item_ext, &ei_tcpclv4_extitem_critical);
1581 }
1582
1583 uint16_t extitem_type = tvb_get_uint16(tvb, offset + extlist_offset + extitem_offset, ENC_BIG_ENDIAN0x00000000);
1584 proto_item *item_type = proto_tree_add_uint(tree_ext, hf_tcpclv4_sessext_type, tvb, offset + extlist_offset + extitem_offset, 2, extitem_type);
1585 extitem_offset += 2;
1586
1587 dissector_handle_t subdis = dissector_get_uint_handle(xfer_ext_dissectors, extitem_type);
1588 const char *subname = dissector_handle_get_description(subdis);
1589 if (subdis) {
1590 proto_item_set_text(item_type, "Item Type: %s (0x%04" PRIx16"hx" ")", subname, extitem_type);
1591 }
1592
1593 uint16_t extitem_len = tvb_get_uint16(tvb, offset + extlist_offset + extitem_offset, ENC_BIG_ENDIAN0x00000000);
1594 proto_tree_add_uint(tree_ext, hf_tcpclv4_sessext_len, tvb, offset + extlist_offset + extitem_offset, 2, extitem_len);
1595 extitem_offset += 2;
1596
1597 tvbuff_t *extitem_tvb = tvb_new_subset_length(tvb, offset + extlist_offset + extitem_offset, extitem_len);
1598 proto_item *item_extdata = proto_tree_add_item(tree_ext, hf_tcpclv4_sessext_data, extitem_tvb, 0, tvb_captured_length(extitem_tvb), ENC_NA0x00000000);
1599 proto_tree *tree_extdata = proto_item_add_subtree(item_extdata, ett_tcpclv4_sessext_data);
1600
1601 int sublen = 0;
1602 if (subdis) {
1603 sublen = call_dissector_only(subdis, extitem_tvb, pinfo, tree_extdata, NULL((void*)0));
1604 }
1605 if (sublen == 0) {
1606 expert_add_info(pinfo, item_type, &ei_tcpclv4_invalid_sessext_type);
1607 }
1608 extitem_offset += extitem_len;
1609
1610 proto_item_set_len(item_ext, extitem_offset);
1611 extlist_offset += extitem_offset;
1612
1613 if (subname) {
1614 proto_item_append_text(item_ext, ": %s", subname);
1615 }
1616 else {
1617 proto_item_append_text(item_ext, ": Type 0x%04" PRIx16"hx", extitem_type);
1618 }
1619 if (is_critical) {
1620 proto_item_append_text(item_ext, ", CRITICAL");
1621 }
1622 }
1623 // advance regardless of any internal offset processing
1624 offset += extlist_len;
1625
1626 if (ctx->tx_peer->sess_init_seen) {
1627 if (tcpcl_analyze_sequence) {
1628 if (!tcpcl_frame_loc_equal(ctx->tx_peer->sess_init_seen, ctx->cur_loc)) {
1629 expert_add_info(pinfo, item_msg, &ei_tcpclv4_sess_init_duplicate);
1630 }
1631 }
1632 }
1633 else {
1634 ctx->tx_peer->sess_init_seen = tcpcl_frame_loc_clone(wmem_file_scope(), ctx->cur_loc);
1635 ctx->tx_peer->keepalive = keepalive;
1636 ctx->tx_peer->segment_mru = seg_mru;
1637 ctx->tx_peer->transfer_mru = xfer_mru;
1638 }
1639
1640 break;
1641 }
1642 case TCPCLV4_MSGTYPE_SESS_TERM: {
1643 uint8_t flags = tvb_get_uint8(tvb, offset);
1644 proto_tree_add_bitmask(tree_msg, tvb, offset, hf_tcpclv4_sess_term_flags, ett_tcpclv4_sess_term_flags, v4_sess_term_flags, ENC_BIG_ENDIAN0x00000000);
1645 offset += 1;
1646
1647 uint8_t reason = tvb_get_uint8(tvb, offset);
1648 proto_tree_add_uint(tree_msg, hf_tcpclv4_sess_term_reason, tvb, offset, 1, reason);
1649 offset += 1;
1650
1651 if (ctx->tx_peer->sess_term_seen) {
1652 if (tcpcl_analyze_sequence) {
1653 if (!tcpcl_frame_loc_equal(ctx->tx_peer->sess_term_seen, ctx->cur_loc)) {
1654 expert_add_info(pinfo, item_msg, &ei_tcpclv4_sess_term_duplicate);
1655 }
1656 }
1657 }
1658 else {
1659 ctx->tx_peer->sess_term_seen = tcpcl_frame_loc_clone(wmem_file_scope(), ctx->cur_loc);
1660 ctx->tx_peer->sess_term_reason = reason;
1661 }
1662
1663 if (tcpcl_analyze_sequence) {
1664 if (ctx->rx_peer->sess_term_seen) {
1665 proto_item *item_rel = proto_tree_add_uint(tree_msg, hf_tcpclv4_sess_term_related, tvb, 0, 0, ctx->rx_peer->sess_term_seen->frame_num);
1666 proto_item_set_generated(item_rel);
1667
1668 // Is this message after the other SESS_TERM?
1669 if (tcpcl_frame_loc_compare(ctx->tx_peer->sess_term_seen, ctx->rx_peer->sess_term_seen, NULL((void*)0)) > 0) {
1670 if (!(flags & TCPCLV4_SESS_TERM_FLAG_REPLY)) {
1671 expert_add_info(pinfo, item_msg, &ei_tcpclv4_sess_term_reply_flag);
1672 }
1673 }
1674 }
1675 }
1676
1677 break;
1678 }
1679 case TCPCLV4_MSGTYPE_XFER_SEGMENT:{
1680 uint8_t flags = tvb_get_uint8(tvb, offset);
1681 proto_item *item_flags = proto_tree_add_bitmask(tree_msg, tvb, offset, hf_tcpclv4_xfer_flags, ett_tcpclv4_xfer_flags, v4_xfer_flags, ENC_BIG_ENDIAN0x00000000);
1682 offset += 1;
1683
1684 uint64_t xfer_id = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1685 proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_id, tvb, offset, 8, xfer_id);
1686 offset += 8;
1687
1688 if (flags & TCPCLV4_TRANSFER_FLAG_START) {
1689 uint32_t extlist_len = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1690 proto_tree_add_uint(tree_msg, hf_tcpclv4_xfer_segment_extlist_len, tvb, offset, 4, extlist_len);
1691 offset += 4;
1692
1693 int extlist_offset = 0;
1694 while (extlist_offset < (int)extlist_len) {
1695 int extitem_offset = 0;
1696 proto_item *item_ext = proto_tree_add_item(tree_msg, hf_tcpclv4_xferext_tree, tvb, offset + extlist_offset, 0, ENC_NA0x00000000);
1697 proto_tree *tree_ext = proto_item_add_subtree(item_ext, ett_tcpclv4_xferext);
1698
1699 uint8_t extitem_flags = tvb_get_uint8(tvb, offset + extlist_offset + extitem_offset);
1700 proto_tree_add_bitmask(tree_ext, tvb, offset + extlist_offset + extitem_offset, hf_tcpclv4_xferext_flags, ett_tcpclv4_xferext_flags, v4_xferext_flags, ENC_BIG_ENDIAN0x00000000);
1701 extitem_offset += 1;
1702 const bool_Bool is_critical = (extitem_flags & TCPCLV4_EXTENSION_FLAG_CRITICAL);
1703 if (is_critical) {
1704 expert_add_info(pinfo, item_ext, &ei_tcpclv4_extitem_critical);
1705 }
1706
1707 uint16_t extitem_type = tvb_get_uint16(tvb, offset + extlist_offset + extitem_offset, ENC_BIG_ENDIAN0x00000000);
1708 proto_item *item_type = proto_tree_add_uint(tree_ext, hf_tcpclv4_xferext_type, tvb, offset + extlist_offset + extitem_offset, 2, extitem_type);
1709 extitem_offset += 2;
1710
1711 dissector_handle_t subdis = dissector_get_uint_handle(xfer_ext_dissectors, extitem_type);
1712 const char *subname = dissector_handle_get_description(subdis);
1713 if (subdis) {
1714 proto_item_set_text(item_type, "Item Type: %s (0x%04" PRIx16"hx" ")", subname, extitem_type);
1715 }
1716
1717 uint16_t extitem_len = tvb_get_uint16(tvb, offset + extlist_offset + extitem_offset, ENC_BIG_ENDIAN0x00000000);
1718 proto_tree_add_uint(tree_ext, hf_tcpclv4_xferext_len, tvb, offset + extlist_offset + extitem_offset, 2, extitem_len);
1719 extitem_offset += 2;
1720
1721 tvbuff_t *extitem_tvb = tvb_new_subset_length(tvb, offset + extlist_offset + extitem_offset, extitem_len);
1722 proto_item *item_extdata = proto_tree_add_item(tree_ext, hf_tcpclv4_xferext_data, extitem_tvb, 0, tvb_captured_length(extitem_tvb), ENC_NA0x00000000);
1723 proto_tree *tree_extdata = proto_item_add_subtree(item_extdata, ett_tcpclv4_xferext_data);
1724
1725 tcpcl_frame_loc_t *extitem_loc = tcpcl_frame_loc_new(pinfo->pool, pinfo, extitem_tvb, 0);
1726 tcpcl_peer_associate_transfer(ctx->tx_peer, extitem_loc, xfer_id);
1727
1728 int sublen = 0;
1729 if (subdis) {
1730 sublen = call_dissector_only(subdis, extitem_tvb, pinfo, tree_extdata, NULL((void*)0));
1731 }
1732 if (sublen == 0) {
1733 expert_add_info(pinfo, item_type, &ei_tcpclv4_invalid_xferext_type);
1734 }
1735 extitem_offset += extitem_len;
1736
1737 proto_item_set_len(item_ext, extitem_offset);
1738 extlist_offset += extitem_offset;
1739
1740 if (subname) {
1741 proto_item_append_text(item_ext, ": %s", subname);
1742 }
1743 else {
1744 proto_item_append_text(item_ext, ": Type 0x%04" PRIx16"hx", extitem_type);
1745 }
1746 if (is_critical) {
1747 proto_item_append_text(item_ext, ", CRITICAL");
1748 }
1749 }
1750 // advance regardless of any internal offset processing
1751 offset += extlist_len;
1752 }
1753
1754 uint64_t data_len = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1755 proto_item *item_len = proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_segment_data_len, tvb, offset, 8, data_len);
1756 offset += 8;
1757
1758 if (data_len > ctx->rx_peer->segment_mru) {
1759 expert_add_info(pinfo, item_len, &ei_tcpclv4_xfer_seg_over_seg_mru);
1760 }
1761 const int data_len_clamp = get_clamped_length(data_len, pinfo, item_len);
1762
1763 // Treat data as payload layer
1764 const int data_offset = offset;
1765 proto_tree_add_item(tree_msg, hf_tcpclv4_xfer_segment_data, tvb, offset, data_len_clamp, ENC_NA0x00000000);
1766 offset += data_len_clamp;
1767 payload_len = data_len_clamp;
1768
1769 wmem_strbuf_append_printf(suffix_text, ", Xfer ID: %" PRIi64"l" "i", xfer_id);
1770
1771 if (flags) {
1772 wmem_strbuf_append(suffix_text, ", Flags: ");
1773 bool_Bool sep = false0;
1774 if (flags & TCPCLV4_TRANSFER_FLAG_START) {
1775 wmem_strbuf_append(suffix_text, "START");
1776 sep = true1;
1777 }
1778 if (flags & TCPCLV4_TRANSFER_FLAG_END) {
1779 if (sep) {
1780 wmem_strbuf_append(suffix_text, "|");
1781 }
1782 wmem_strbuf_append(suffix_text, "END");
1783 }
1784 }
1785
1786 if (tcpcl_analyze_sequence) {
1787 transfer_add_segment(ctx, xfer_id, flags, data_len, pinfo, tvb, tree_msg, item_msg, item_flags);
1788 }
1789
1790 if (tcpcl_desegment_transfer) {
1791 // Reassemble the segments
1792 fragment_head *xferload_frag_msg = fragment_add_seq_next(
1793 &xfer_reassembly_table,
1794 tvb, data_offset,
1795 pinfo, 0, &xfer_id,
1796 data_len_clamp,
1797 !(flags & TCPCLV4_TRANSFER_FLAG_END)
1798 );
1799 ctx->xferload = process_reassembled_data(
1800 tvb, data_offset, pinfo,
1801 "Reassembled Transfer",
1802 xferload_frag_msg,
1803 &xfer_frag_items,
1804 NULL((void*)0),
1805 tree
1806 );
1807 }
1808
1809 break;
1810 }
1811 case TCPCLV4_MSGTYPE_XFER_ACK:{
1812 uint8_t flags = tvb_get_uint8(tvb, offset);
1813 proto_item *item_flags = proto_tree_add_bitmask(tree_msg, tvb, offset, hf_tcpclv4_xfer_flags, ett_tcpclv4_xfer_flags, v4_xfer_flags, ENC_BIG_ENDIAN0x00000000);
1814 offset += 1;
1815
1816 uint64_t xfer_id = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1817 proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_id, tvb, offset, 8, xfer_id);
1818 offset += 8;
1819
1820 uint64_t ack_len = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1821 proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_ack_ack_len, tvb, offset, 8, ack_len);
1822 offset += 8;
1823
1824 wmem_strbuf_append_printf(suffix_text, ", Xfer ID: %" PRIi64"l" "i", xfer_id);
1825
1826 if (flags) {
1827 wmem_strbuf_append(suffix_text, ", Flags: ");
1828 bool_Bool sep = false0;
1829 if (flags & TCPCLV4_TRANSFER_FLAG_START) {
1830 wmem_strbuf_append(suffix_text, "START");
1831 sep = true1;
1832 }
1833 if (flags & TCPCLV4_TRANSFER_FLAG_END) {
1834 if (sep) {
1835 wmem_strbuf_append(suffix_text, "|");
1836 }
1837 wmem_strbuf_append(suffix_text, "END");
1838 }
1839 }
1840
1841 if (tcpcl_analyze_sequence) {
1842 transfer_add_ack(ctx, xfer_id, flags, ack_len, pinfo, tvb, tree_msg, item_msg, item_flags);
1843 }
1844
1845 break;
1846 }
1847 case TCPCLV4_MSGTYPE_XFER_REFUSE: {
1848 uint8_t reason = tvb_get_uint8(tvb, offset);
1849 proto_tree_add_uint(tree_msg, hf_tcpclv4_xfer_refuse_reason, tvb, offset, 1, reason);
1850 offset += 1;
1851
1852 uint64_t xfer_id = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1853 proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_id, tvb, offset, 8, xfer_id);
1854 offset += 8;
1855
1856 wmem_strbuf_append_printf(suffix_text, ", Xfer ID: %" PRIi64"l" "i", xfer_id);
1857
1858 if (tcpcl_analyze_sequence) {
1859 transfer_add_refuse(ctx, xfer_id, pinfo, tvb, tree_msg, item_msg);
1860 }
1861
1862 break;
1863 }
1864 case TCPCLV4_MSGTYPE_KEEPALIVE: {
1865 break;
1866 }
1867 case TCPCLV4_MSGTYPE_MSG_REJECT: {
1868 uint8_t reason = tvb_get_uint8(tvb, offset);
1869 proto_tree_add_uint(tree_msg, hf_tcpclv4_msg_reject_reason, tvb, offset, 1, reason);
1870 offset += 1;
1871
1872 uint8_t rej_head = tvb_get_uint8(tvb, offset);
1873 proto_tree_add_uint(tree_msg, hf_tcpclv4_msg_reject_head, tvb, offset, 1, rej_head);
1874 offset += 1;
1875
1876 break;
1877 }
1878 default:
1879 expert_add_info(pinfo, item_msg, &ei_tcpclv4_invalid_msg_type);
1880 break;
1881 }
1882
1883 proto_item_set_len(item_msg, offset - payload_len);
1884 proto_item_append_text(item_msg, ": %s%s", msgtype_name, wmem_strbuf_get_str(suffix_text));
1885 wmem_strbuf_finalize(suffix_text);
1886
1887 if (tcpcl_analyze_sequence) {
1888 if (!(ctx->tx_peer->chdr_missing)) {
1889 // assume the capture is somewhere in the middle
1890 if (!(ctx->tx_peer->sess_init_seen)) {
1891 expert_add_info(pinfo, item_msg, &ei_tcpclv4_sess_init_missing);
1892 }
1893 else {
1894 // This message is before SESS_INIT (but is not the SESS_INIT)
1895 const int cmp_sess_init = tcpcl_frame_loc_compare(ctx->cur_loc, ctx->tx_peer->sess_init_seen, NULL((void*)0));
1896 if (((msgtype == TCPCLV4_MSGTYPE_SESS_INIT) && (cmp_sess_init < 0))
1897 || ((msgtype != TCPCLV4_MSGTYPE_SESS_INIT) && (cmp_sess_init <= 0))) {
1898 expert_add_info(pinfo, item_msg, &ei_tcpclv4_sess_init_missing);
1899 }
1900 }
1901 }
1902 }
1903
1904 if (msgtype_name) {
1905 col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), msgtype_name);
1906 }
1907
1908 try_negotiate(ctx, pinfo);
1909 // Show negotiation results
1910 if (msgtype == TCPCLV4_MSGTYPE_SESS_INIT) {
1911 if (ctx->convo->sess_negotiated) {
1912 if (ctx->rx_peer->sess_init_seen){
1913 proto_item *item_nego = proto_tree_add_uint(tree_msg, hf_tcpclv4_sess_init_related, tvb, 0, 0, ctx->rx_peer->sess_init_seen->frame_num);
1914 proto_item_set_generated(item_nego);
1915 }
1916 {
1917 proto_item *item_nego = proto_tree_add_uint(tree_msg, hf_tcpclv4_negotiate_keepalive, tvb, 0, 0, ctx->convo->sess_keepalive);
1918 proto_item_set_generated(item_nego);
1919 }
1920 }
1921 }
1922
1923 return offset;
1924}
1925
1926/** Function to extract a message length, or zero if not valid.
1927 * This will call set_chdr_missing() if valid.
1928 */
1929typedef unsigned (*chdr_missing_check)(packet_info *, tvbuff_t *, int offset, tcpcl_dissect_ctx_t *);
1930
1931/** Inspect a single segment to determine if this looks like a TLS record set.
1932 */
1933static unsigned chdr_missing_tls(packet_info *pinfo, tvbuff_t *tvb, int offset,
1934 tcpcl_dissect_ctx_t *ctx) {
1935 if (ctx->convo->session_tls_start) {
1936 // already in a TLS context
1937 return 0;
1938 }
1939
1940 // similar heuristics to is_sslv3_or_tls() from packet-tls.c
1941 if (tvb_captured_length(tvb) < 5) {
1942 return 0;
1943 }
1944 uint8_t rectype = tvb_get_uint8(tvb, offset);
1945 uint16_t recvers = tvb_get_uint16(tvb, offset+1, ENC_BIG_ENDIAN0x00000000);
1946 uint16_t reclen = tvb_get_uint16(tvb, offset+1+2, ENC_BIG_ENDIAN0x00000000);
1947
1948 switch(rectype) {
1949 // These overlap with TCPCLV3_DATA_SEGMENT but have invalid flags
1950 // They are valid but unallocated v4 message type codes
1951 case SSL_ID_ALERT:
1952 case SSL_ID_HANDSHAKE:
1953 case SSL_ID_APP_DATA:
1954 case SSL_ID_HEARTBEAT:
1955 break;
1956 default:
1957 return 0;
1958 }
1959 if ((recvers & 0xFF00) != 0x0300) {
1960 return 0;
1961 }
1962 if (reclen == 0 || reclen >= TLS_MAX_RECORD_LENGTH0x4000 + 2048) {
1963 return 0;
1964 }
1965
1966 // post-STARTTLS
1967 ctx->convo->session_use_tls = true1;
1968 ctx->convo->session_tls_start = tcpcl_frame_loc_clone(wmem_file_scope(), ctx->cur_loc);
1969 ssl_starttls_post_ack(tls_handle, pinfo, tcpcl_handle);
1970
1971 return tvb_reported_length(tvb);
1972
1973}
1974
1975static unsigned chdr_missing_v3(packet_info *pinfo, tvbuff_t *tvb, int offset,
1976 tcpcl_dissect_ctx_t *ctx) {
1977 unsigned sublen = get_v3_msg_len(pinfo, tvb, offset, ctx);
1978 if (sublen > 0) {
1979 set_chdr_missing(ctx->tx_peer, 3);
1980 }
1981 return sublen;
1982}
1983
1984static unsigned chdr_missing_v4(packet_info *pinfo, tvbuff_t *tvb, int offset,
1985 tcpcl_dissect_ctx_t *ctx) {
1986 unsigned sublen = get_v4_msg_len(pinfo, tvb, offset, ctx);
1987 if (sublen > 0) {
1988 set_chdr_missing(ctx->tx_peer, 4);
1989 }
1990 return sublen;
1991}
1992
1993static const chdr_missing_check chdr_missing_v3first[] = {
1994 &chdr_missing_tls,
1995 &chdr_missing_v3,
1996 &chdr_missing_v4,
1997 NULL((void*)0)
1998};
1999static const chdr_missing_check chdr_missing_v3only[] = {
2000 &chdr_missing_v3,
2001 NULL((void*)0)
2002};
2003static const chdr_missing_check chdr_missing_v4first[] = {
2004 &chdr_missing_tls,
2005 &chdr_missing_v4,
2006 &chdr_missing_v3,
2007 NULL((void*)0)
2008};
2009static const chdr_missing_check chdr_missing_v4only[] = {
2010 &chdr_missing_v4,
2011 NULL((void*)0)
2012};
2013
2014static unsigned get_message_len(packet_info *pinfo, tvbuff_t *tvb, int ext_offset, void *data _U___attribute__((unused))) {
2015 tcpcl_dissect_ctx_t *ctx = tcpcl_dissect_ctx_get(tvb, pinfo, ext_offset);
2016 if (!ctx) {
2017 return 0;
2018 }
2019 const unsigned init_offset = ext_offset;
2020 unsigned offset = ext_offset;
2021
2022 if (ctx->is_contact) {
2023 if (tvb_memeql(tvb, offset, magic, sizeof(magic)) != 0) {
2024 // Optional heuristic dissection of a message
2025 const chdr_missing_check *checks = NULL((void*)0);
2026 switch (tcpcl_chdr_missing) {
2027 case CHDRMSN_V3FIRST:
2028 checks = chdr_missing_v3first;
2029 break;
2030 case CHDRMSN_V3ONLY:
2031 checks = chdr_missing_v3only;
2032 break;
2033 case CHDRMSN_V4FIRST:
2034 checks = chdr_missing_v4first;
2035 break;
2036 case CHDRMSN_V4ONLY:
2037 checks = chdr_missing_v4only;
2038 break;
2039 }
2040 if (checks) {
2041 for (const chdr_missing_check *chk = checks; *chk; ++chk) {
2042 unsigned sublen = (**chk)(pinfo, tvb, offset, ctx);
2043 if (sublen > 0) {
2044 return sublen;
2045 }
2046 }
2047 // no match
2048 return 0;
2049 }
2050 else {
2051 // require the contact header
2052 const unsigned available = tvb_captured_length(tvb) - offset;
2053 if (available < sizeof(magic) + 1) {
2054 return DESEGMENT_ONE_MORE_SEGMENT0x0fffffff;
2055 }
2056 // sufficient size available but no match
2057 return 0;
2058 }
2059 }
2060 offset += sizeof(magic);
2061
2062 uint8_t version = tvb_get_uint8(tvb, offset);
2063 offset += 1;
2064 if (version == 3) {
2065 offset += 3; // flags + keepalive
2066 uint64_t eid_len;
2067 const unsigned bytecount = tvb_get_sdnv(tvb, offset, &eid_len);
2068 const int len_clamp = get_clamped_length(eid_len, NULL((void*)0), NULL((void*)0));
2069 offset += bytecount + len_clamp;
2070 }
2071 else if (version == 4) {
2072 offset += 1; // flags
2073 }
2074 else {
2075 return 0;
2076 }
2077 }
2078 else {
2079 if (ctx->tx_peer->version == 3) {
2080 unsigned sublen = get_v3_msg_len(pinfo, tvb, offset, ctx);
2081 if (sublen == 0) {
2082 return 0;
2083 }
2084 offset += sublen;
2085 }
2086 else if (ctx->tx_peer->version == 4) {
2087 unsigned sublen = get_v4_msg_len(pinfo, tvb, offset, ctx);
2088 if (sublen == 0) {
2089 return 0;
2090 }
2091 offset += sublen;
2092 }
2093 else {
2094 return 0;
2095 }
2096 }
2097 const int needlen = offset - init_offset;
2098 return needlen;
2099}
2100
2101static int dissect_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused))) {
2102 unsigned offset = 0;
2103 tcpcl_dissect_ctx_t *ctx = tcpcl_dissect_ctx_get(tvb, pinfo, offset);
2104 if (!ctx) {
2105 return 0;
2106 }
2107
2108 {
2109 const char *proto_name = col_get_text(pinfo->cinfo, COL_PROTOCOL);
2110 if (g_strcmp0(proto_name, proto_name_tcpcl) != 0) {
2111 col_set_str(pinfo->cinfo, COL_PROTOCOL, proto_name_tcpcl);
2112 col_clear(pinfo->cinfo, COL_INFO);
2113 }
2114 }
2115
2116 // Append to the last TCPCL tree item if there is one
2117 proto_item *item_tcpcl;
2118 proto_tree *tree_tcpcl;
2119 bool_Bool is_new_item_tcpcl = false0;
2120 if (tree && (tree->last_child)
2121 && (PITEM_HFINFO(tree->last_child)((tree->last_child)->hfinfo)->id == proto_tcpcl)) {
2122 item_tcpcl = tree->last_child;
2123 tree_tcpcl = proto_item_get_subtree(item_tcpcl);
2124 }
2125 else {
2126 item_tcpcl = proto_tree_add_item(tree, proto_tcpcl, tvb, 0, -1, ENC_NA0x00000000);
2127 tree_tcpcl = proto_item_add_subtree(item_tcpcl, ett_proto_tcpcl);
2128 is_new_item_tcpcl = true1;
2129 }
2130
2131 if (ctx->tx_peer->chdr_missing) {
2132 expert_add_info(pinfo, item_tcpcl, &ei_chdr_missing);
2133 }
2134 if (ctx->is_contact) {
2135 col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), "Contact Header");
2136
2137 proto_item *item_chdr = proto_tree_add_item(tree_tcpcl, hf_chdr_tree, tvb, offset, -1, ENC_NA0x00000000);
2138 proto_tree *tree_chdr = proto_item_add_subtree(item_chdr, ett_chdr);
2139
2140 proto_item *item_magic = proto_tree_add_item(tree_chdr, hf_chdr_magic, tvb, offset, sizeof(magic), ENC_NA0x00000000);
2141 if (tvb_memeql(tvb, offset, magic, sizeof(magic)) != 0) {
2142 expert_add_info(pinfo, item_magic, &ei_invalid_magic);
2143 return 0;
2144 }
2145 offset += sizeof(magic);
2146
2147 ctx->tx_peer->version = tvb_get_uint8(tvb, offset);
2148 proto_item *item_version = proto_tree_add_uint(tree_chdr, hf_chdr_version, tvb, offset, 1, ctx->tx_peer->version);
2149 offset += 1;
2150
2151 // Mark or check version match
2152 if (!ctx->convo->version) {
2153 ctx->convo->version = wmem_new(wmem_file_scope(), uint8_t)((uint8_t*)wmem_alloc((wmem_file_scope()), sizeof(uint8_t)));
2154 *(ctx->convo->version) = ctx->tx_peer->version;
2155 }
2156 else if (*(ctx->convo->version) != ctx->tx_peer->version) {
2157 expert_add_info(pinfo, item_version, &ei_mismatch_version);
2158 }
2159
2160 if ((ctx->tx_peer->version < 3) || (ctx->tx_peer->version > 4)) {
2161 expert_add_info(pinfo, item_version, &ei_invalid_version);
2162 return offset;
2163 }
2164
2165 if (ctx->tx_peer->version == 3) {
2166 /* Subtree to expand the bits in the Contact Header Flags */
2167 proto_tree_add_bitmask(tree_chdr, tvb, offset, hf_tcpclv3_chdr_flags, ett_tcpclv3_chdr_flags, v3_chdr_flags, ENC_BIG_ENDIAN0x00000000);
2168 offset++;
2169
2170 proto_tree_add_item(tree_chdr, hf_tcpclv3_chdr_keep_alive, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000);
2171 offset += 2;
2172
2173 /*
2174 * New format Contact header has length field followed by EID.
2175 */
2176 uint64_t eid_length;
2177 unsigned sdnv_length;
2178 proto_item *sub_item = proto_tree_add_item_ret_varint(tree_chdr, hf_tcpclv3_chdr_local_eid_length, tvb, offset, -1, ENC_VARINT_SDNV0x00000010, &eid_length, &sdnv_length);
2179 offset += sdnv_length;
2180 const int eid_len_clamp = get_clamped_length(eid_length, pinfo, sub_item);
2181
2182 proto_tree_add_item(tree_chdr, hf_tcpclv3_chdr_local_eid, tvb, offset, eid_len_clamp, ENC_ASCII0x00000000);
2183 offset += eid_len_clamp;
2184
2185 // assumed parameters
2186 ctx->tx_peer->segment_mru = UINT64_MAX(18446744073709551615UL);
2187 ctx->tx_peer->transfer_mru = UINT64_MAX(18446744073709551615UL);
2188 }
2189 else { /* (version == 4) */
2190 uint8_t flags = tvb_get_uint8(tvb, offset);
2191 proto_tree_add_bitmask(tree_chdr, tvb, offset, hf_tcpclv4_chdr_flags, ett_tcpclv4_chdr_flags, v4_chdr_flags, ENC_BIG_ENDIAN0x00000000);
2192 offset += 1;
2193
2194 ctx->tx_peer->can_tls = (flags & TCPCLV4_CONTACT_FLAG_CANTLS);
2195 }
2196
2197 proto_item_set_len(item_chdr, offset);
2198
2199 if (ctx->tx_peer->chdr_seen) {
2200 if (tcpcl_analyze_sequence) {
2201 if (!tcpcl_frame_loc_equal(ctx->tx_peer->chdr_seen, ctx->cur_loc)) {
2202 expert_add_info(pinfo, item_chdr, &ei_chdr_duplicate);
2203 }
2204 }
2205 }
2206 else {
2207 ctx->tx_peer->chdr_seen = tcpcl_frame_loc_clone(wmem_file_scope(), ctx->cur_loc);
2208 }
2209
2210 try_negotiate(ctx, pinfo);
2211 // Show negotiation results
2212 if (ctx->convo->contact_negotiated) {
2213 if (ctx->rx_peer->chdr_seen) {
2214 proto_item *item_nego = proto_tree_add_uint(tree_chdr, hf_chdr_related, tvb, 0, 0, ctx->rx_peer->chdr_seen->frame_num);
2215 proto_item_set_generated(item_nego);
2216 }
2217 if (ctx->tx_peer->version == 4) {
2218 proto_item *item_nego = proto_tree_add_boolean(tree_chdr, hf_tcpclv4_negotiate_use_tls, tvb, 0, 0, ctx->convo->session_use_tls);
2219 proto_item_set_generated(item_nego);
2220 }
2221 }
2222 }
2223 else {
2224 if (ctx->tx_peer->version == 3) {
2225 offset += dissect_v3_msg(tvb, pinfo, tree_tcpcl, ctx);
2226 }
2227 else if (ctx->tx_peer->version == 4) {
2228 offset += dissect_v4_msg(tvb, pinfo, tree_tcpcl, ctx);
2229 }
2230 }
2231
2232 if (is_new_item_tcpcl) {
2233 proto_item_set_len(item_tcpcl, offset);
2234 proto_item_append_text(item_tcpcl, " Version %d", ctx->tx_peer->version);
2235 }
2236 else {
2237 proto_item_set_len(item_tcpcl, proto_item_get_len(item_tcpcl) + offset);
2238 }
2239
2240 if (ctx->xferload) {
2241 col_append_str(pinfo->cinfo, COL_INFO, " [Bundle]");
2242
2243 if (tcpcl_decode_bundle) {
2244 if (bundle_handle) {
2245 call_dissector(
2246 bundle_handle,
2247 ctx->xferload,
2248 pinfo,
2249 tree
2250 );
2251 }
2252 }
2253 }
2254
2255 return offset;
2256}
2257
2258static int
2259dissect_tcpcl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused)))
2260{
2261 /* Retrieve information from conversation, or add it if it isn't
2262 * there yet */
2263 conversation_t *convo = find_or_create_conversation(pinfo);
2264 tcpcl_conversation_t *tcpcl_convo = (tcpcl_conversation_t *)conversation_get_proto_data(convo, proto_tcpcl);
2265 if (!tcpcl_convo) {
2266 tcpcl_convo = tcpcl_conversation_new();
2267 conversation_add_proto_data(convo, proto_tcpcl, tcpcl_convo);
2268 // Assume the first source (i.e. TCP initiator) is the active node
2269 copy_address_wmem(wmem_file_scope(), &(tcpcl_convo->active->addr), &(pinfo->src));
2270 tcpcl_convo->active->port = pinfo->srcport;
2271 copy_address_wmem(wmem_file_scope(), &(tcpcl_convo->passive->addr), &(pinfo->dst));
2272 tcpcl_convo->passive->port = pinfo->destport;
2273 }
2274
2275 tcp_dissect_pdus(tvb, pinfo, tree, true1, 1, get_message_len, dissect_message, NULL((void*)0));
2276
2277 const unsigned buflen = tvb_captured_length(tvb);
2278 return buflen;
2279}
2280
2281static bool_Bool
2282dissect_tcpcl_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2283{
2284 if (tvb_reported_length(tvb) < minimum_chdr_size) {
2285 return false0;
2286 }
2287 if (tvb_memeql(tvb, 0, magic, sizeof(magic)) != 0) {
2288 return false0;
2289 }
2290
2291 // treat the rest of the connection as TCPCL
2292 conversation_t *convo = find_or_create_conversation(pinfo);
2293 conversation_set_dissector(convo, tcpcl_handle);
2294
2295 dissect_tcpcl(tvb, pinfo, tree, data);
2296 return true1;
2297}
2298
2299static int dissect_xferext_transferlen(tvbuff_t *tvb, packet_info *pinfo _U___attribute__((unused)), proto_tree *tree, void *data _U___attribute__((unused))) {
2300 unsigned offset = 0;
2301 tcpcl_dissect_ctx_t *ctx = tcpcl_dissect_ctx_get(tvb, pinfo, offset);
2302 if (!ctx) {
2303 return 0;
2304 }
2305
2306 uint64_t total_len = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN0x00000000);
2307 proto_item *item_len = proto_tree_add_uint64(tree, hf_tcpclv4_xferext_transferlen_total_len, tvb, offset, 8, total_len);
2308 offset += 8;
2309 if (total_len > ctx->rx_peer->transfer_mru) {
2310 expert_add_info(pinfo, item_len, &ei_tcpclv4_xferload_over_xfer_mru);
2311 }
2312
2313 if (tcpcl_analyze_sequence) {
2314 uint64_t *xfer_id = wmem_map_lookup(ctx->tx_peer->frame_loc_to_transfer, ctx->cur_loc);
2315 if (xfer_id) {
2316 tcpcl_transfer_t *xfer = get_or_create_transfer_t(ctx->tx_peer->transfers, *xfer_id);
2317 xfer->total_length = wmem_new(wmem_file_scope(), uint64_t)((uint64_t*)wmem_alloc((wmem_file_scope()), sizeof(uint64_t))
)
;
2318 *(xfer->total_length) = total_len;
2319 }
2320 }
2321
2322 return offset;
2323}
2324
2325static int dissect_othername_bundleeid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused))) {
2326 unsigned offset = 0;
2327 asn1_ctx_t actx;
2328 asn1_ctx_init(&actx, ASN1_ENC_BER, true1, pinfo);
2329 offset += dissect_ber_restricted_string(
2330 false0, BER_UNI_TAG_IA5String22,
2331 &actx, tree, tvb, offset, hf_othername_bundleeid, NULL((void*)0)
2332 );
2333 return offset;
2334}
2335
2336/// Re-initialize after a configuration change
2337static void reinit_tcpcl(void) {
2338}
2339
2340void
2341proto_register_tcpcl(void)
2342{
2343 expert_module_t *expert_tcpcl;
2344
2345 proto_tcpcl = proto_register_protocol("DTN TCP Convergence Layer Protocol", "TCPCL", "tcpcl");
2346
2347 proto_tcpcl_exts = proto_register_protocol_in_name_only(
2348 "TCPCL Extension Subdissectors",
2349 "TCPCL Extension Subdissectors",
2350 "tcpcl_exts",
2351 proto_tcpcl,
2352 FT_PROTOCOL
2353 );
2354
2355 proto_register_field_array(proto_tcpcl, hf_tcpcl, array_length(hf_tcpcl)(sizeof (hf_tcpcl) / sizeof (hf_tcpcl)[0]));
2356 proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0]));
2357 expert_tcpcl = expert_register_protocol(proto_tcpcl);
2358 expert_register_field_array(expert_tcpcl, ei_tcpcl, array_length(ei_tcpcl)(sizeof (ei_tcpcl) / sizeof (ei_tcpcl)[0]));
2359
2360 tcpcl_handle = register_dissector("tcpcl", dissect_tcpcl, proto_tcpcl);
2361 sess_ext_dissectors = register_dissector_table("tcpcl.v4.sess_ext", "TCPCLv4 Session Extension", proto_tcpcl, FT_UINT16, BASE_HEX);
2362 xfer_ext_dissectors = register_dissector_table("tcpcl.v4.xfer_ext", "TCPCLv4 Transfer Extension", proto_tcpcl, FT_UINT16, BASE_HEX);
2363
2364 module_t *module_tcpcl = prefs_register_protocol(proto_tcpcl, reinit_tcpcl);
2365 prefs_register_enum_preference(
2366 module_tcpcl,
2367 "allow_chdr_missing",
2368 "Allow missing Contact Header",
2369 "Whether the TCPCL dissector should use heuristic "
2370 "dissection of messages in the absence of a Contact Header "
2371 "(if the capture misses the start of session).",
2372 &tcpcl_chdr_missing,
2373 chdr_missing_choices,
2374 false0
2375 );
2376 prefs_register_bool_preference(
2377 module_tcpcl,
2378 "analyze_sequence",
2379 "Analyze message sequences",
2380 "Whether the TCPCL dissector should analyze the sequencing of "
2381 "the messages within each session.",
2382 &tcpcl_analyze_sequence
2383 );
2384 prefs_register_bool_preference(
2385 module_tcpcl,
2386 "desegment_transfer",
2387 "Reassemble the segments of each transfer",
2388 "Whether the TCPCL dissector should combine the sequential segments "
2389 "of a transfer into the full bundle being transferred."
2390 "To use this option, you must also enable "
2391 "\"Allow subdissectors to reassemble TCP streams\" "
2392 "in the TCP protocol settings.",
2393 &tcpcl_desegment_transfer
2394 );
2395 prefs_register_bool_preference(
2396 module_tcpcl,
2397 "decode_bundle",
2398 "Decode bundle data",
2399 "If enabled, the transfer bundle will be decoded.",
2400 &tcpcl_decode_bundle
2401 );
2402
2403 reassembly_table_register(
2404 &xfer_reassembly_table,
2405 &xfer_reassembly_table_functions
2406 );
2407
2408}
2409
2410void
2411proto_reg_handoff_tcpcl(void)
2412{
2413 tls_handle = find_dissector_add_dependency("tls", proto_tcpcl);
2414 bundle_handle = find_dissector("bundle");
2415
2416 dissector_add_uint_with_preference("tcp.port", BUNDLE_PORT4556, tcpcl_handle);
2417 heur_dissector_add("tcp", dissect_tcpcl_heur, "TCPCL over TCP", "tcpcl_tcp", proto_tcpcl, HEURISTIC_ENABLE);
2418
2419 /* Packaged extensions */
2420 {
2421 dissector_handle_t dis_h = create_dissector_handle_with_name_and_description(dissect_xferext_transferlen, proto_tcpcl_exts, NULL((void*)0), "Transfer Length");
2422 dissector_add_uint("tcpcl.v4.xfer_ext", TCPCLV4_XFEREXT_TRANSFER_LEN, dis_h);
2423 }
2424
2425 register_ber_oid_dissector("1.3.6.1.5.5.7.3.35", NULL((void*)0), proto_tcpcl_exts, "id-kp-bundleSecurity");
2426 register_ber_oid_dissector("1.3.6.1.5.5.7.8.11", dissect_othername_bundleeid, proto_tcpcl_exts, "id-on-bundleEID");
2427
2428 reinit_tcpcl();
2429}
2430
2431/*
2432 * Editor modelines - https://www.wireshark.org/tools/modelines.html
2433 *
2434 * Local variables:
2435 * c-basic-offset: 4
2436 * tab-width: 8
2437 * indent-tabs-mode: nil
2438 * End:
2439 *
2440 * vi: set shiftwidth=4 tabstop=8 expandtab:
2441 * :indentSize=4:tabSize=8:noTabs=true:
2442 */