### Bug Summary

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

### Annotated Source Code

Press '?' to see keyboard shortcuts

Show analyzer invocation
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-06-13-100356-3529-1 -x c /builds/wireshark/wireshark/epan/dissectors/packet-tcpcl.c

Keyboard shortcuts:

- Use 'j/k' keys for keyboard navigation
- Use 'Shift+S' to show/hide relevant lines
- Use '?' to toggle this window

Close
Show only relevant lines Show control flow arrows

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 <brian.sipos@gmail.com>
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 <gerald@wireshark.org>
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 |
55 | void proto_register_tcpcl(void);
56 | void proto_reg_handoff_tcpcl(void);
57 |
58 | /// Contact header magic bytes
59 | static const uint8_t magic[] = {'d', 't', 'n', '!'};
60 | /// Minimum size of contact header for any version
61 | static const unsigned minimum_chdr_size = 6;
62 |
63 | /// Options for missing contact header handling
64 | enum AllowContactHeaderMissing {
65 | CHDRMSN_DISABLE,
66 | CHDRMSN_V3FIRST,
67 | CHDRMSN_V3ONLY,
68 | CHDRMSN_V4FIRST,
69 | CHDRMSN_V4ONLY,
70 | };
71 |
72 | static 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 |
81 | static int proto_tcpcl;
82 | static int proto_tcpcl_exts;
83 | /// Protocol column name
84 | static const char *const proto_name_tcpcl = "TCPCL";
85 |
86 | static int tcpcl_chdr_missing = CHDRMSN_V4FIRST;
87 | static bool_Bool tcpcl_desegment_transfer = true1;
88 | static bool_Bool tcpcl_analyze_sequence = true1;
89 | static bool_Bool tcpcl_decode_bundle = true1;
90 |
91 | /* For Reassembling TCP Convergence Layer segments */
92 | static reassembly_table xfer_reassembly_table;
93 |
94 | /// Dissector handles
95 | static dissector_handle_t tcpcl_handle;
96 | static dissector_handle_t tls_handle;
97 | static dissector_handle_t bundle_handle;
98 |
99 | /// Extension sub-dissectors
100 | static dissector_table_t sess_ext_dissectors;
101 | static dissector_table_t xfer_ext_dissectors;
102 |
103 | static 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 */
114 | static 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 |
122 | static 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 |
133 | static 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 |
143 | static 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 |
153 | static 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 |
161 | static int hf_chdr_tree;
162 | static int hf_chdr_magic;
163 | static int hf_chdr_version;
164 | static int hf_chdr_related;
165 |
166 | /* TCP Convergence Header Variables */
167 | static int hf_tcpclv3_mhdr;
168 | static int hf_tcpclv3_pkt_type;
169 |
170 | /* Refuse-Bundle reason code */
171 | static int hf_tcpclv3_refuse_reason_code;
172 |
173 | static int hf_tcpclv3_chdr_flags;
174 | static int hf_tcpclv3_chdr_keep_alive;
175 | static int hf_tcpclv3_chdr_flags_ack_req;
176 | static int hf_tcpclv3_chdr_flags_frag_enable;
177 | static int hf_tcpclv3_chdr_flags_nak;
178 | static int hf_tcpclv3_chdr_local_eid_length;
179 | static int hf_tcpclv3_chdr_local_eid;
180 |
181 | /* TCP Convergence Data Header Variables */
182 | static int hf_tcpclv3_data_procflags;
183 | static int hf_tcpclv3_data_procflags_start;
184 | static int hf_tcpclv3_data_procflags_end;
185 | static int hf_tcpclv3_xfer_id;
186 | static int hf_tcpclv3_data_segment_length;
187 | static int hf_tcpclv3_data_segment_data;
188 |
189 | /* TCP Convergence Ack Variables */
190 | static int hf_tcpclv3_ack_length;
191 |
192 | /* TCP Convergence Shutdown Header Variables */
193 | static int hf_tcpclv3_shutdown_flags;
194 | static int hf_tcpclv3_shutdown_flags_reason;
195 | static int hf_tcpclv3_shutdown_flags_delay;
196 | static int hf_tcpclv3_shutdown_reason;
197 | static int hf_tcpclv3_shutdown_delay;
198 |
199 | static int hf_tcpclv4_chdr_flags;
200 | static int hf_tcpclv4_chdr_flags_cantls;
201 | static int hf_tcpclv4_negotiate_use_tls;
202 |
203 | static int hf_tcpclv4_mhdr_tree;
204 | static int hf_tcpclv4_mhdr_type;
205 | static int hf_tcpclv4_sess_init_keepalive;
206 | static int hf_tcpclv4_sess_init_seg_mru;
207 | static int hf_tcpclv4_sess_init_xfer_mru;
208 | static int hf_tcpclv4_sess_init_nodeid_len;
209 | static int hf_tcpclv4_sess_init_nodeid_data;
210 | static int hf_tcpclv4_sess_init_extlist_len;
211 | static int hf_tcpclv4_sess_init_related;
212 | static int hf_tcpclv4_negotiate_keepalive;
213 |
214 | static int hf_tcpclv4_sess_term_flags;
215 | static int hf_tcpclv4_sess_term_flags_reply;
216 | static int hf_tcpclv4_sess_term_reason;
217 | static int hf_tcpclv4_sess_term_related;
218 |
219 | static int hf_tcpclv4_sessext_tree;
220 | static int hf_tcpclv4_sessext_flags;
221 | static int hf_tcpclv4_sessext_flags_crit;
222 | static int hf_tcpclv4_sessext_type;
223 | static int hf_tcpclv4_sessext_len;
224 | static int hf_tcpclv4_sessext_data;
225 |
226 | static int hf_tcpclv4_xferext_tree;
227 | static int hf_tcpclv4_xferext_flags;
228 | static int hf_tcpclv4_xferext_flags_crit;
229 | static int hf_tcpclv4_xferext_type;
230 | static int hf_tcpclv4_xferext_len;
231 | static int hf_tcpclv4_xferext_data;
232 |
233 | static int hf_tcpclv4_xfer_flags;
234 | static int hf_tcpclv4_xfer_flags_start;
235 | static int hf_tcpclv4_xfer_flags_end;
236 | static int hf_tcpclv4_xfer_id;
237 | static int hf_tcpclv4_xfer_total_len;
238 | static int hf_tcpclv4_xfer_segment_extlist_len;
239 | static int hf_tcpclv4_xfer_segment_data_len;
240 | static int hf_tcpclv4_xfer_segment_data;
241 | static int hf_tcpclv4_xfer_segment_seen_len;
242 | static int hf_tcpclv4_xfer_segment_related_start;
243 | static int hf_tcpclv4_xfer_segment_time_start;
244 | static int hf_tcpclv4_xfer_segment_related_ack;
245 | static int hf_tcpclv4_xfer_segment_time_diff;
246 | static int hf_tcpclv4_xfer_ack_ack_len;
247 | static int hf_tcpclv4_xfer_ack_related_start;
248 | static int hf_tcpclv4_xfer_ack_time_start;
249 | static int hf_tcpclv4_xfer_ack_related_seg;
250 | static int hf_tcpclv4_xfer_ack_time_diff;
251 | static int hf_tcpclv4_xfer_refuse_reason;
252 | static int hf_tcpclv4_xfer_refuse_related_seg;
253 | static int hf_tcpclv4_msg_reject_reason;
254 | static int hf_tcpclv4_msg_reject_head;
255 |
256 | static int hf_tcpclv4_xferext_transferlen_total_len;
257 |
258 | static int hf_othername_bundleeid;
259 |
260 | /*TCP Convergence Layer Reassembly boilerplate*/
261 | static int hf_xfer_segments;
262 | static int hf_xfer_segment;
263 | static int hf_xfer_segment_overlap;
264 | static int hf_xfer_segment_overlap_conflicts;
265 | static int hf_xfer_segment_multiple_tails;
266 | static int hf_xfer_segment_too_long_fragment;
267 | static int hf_xfer_segment_error;
268 | static int hf_xfer_segment_count;
269 | static int hf_xfer_reassembled_in;
270 | static int hf_xfer_reassembled_length;
271 | static int hf_xfer_reassembled_data;
272 |
273 | static 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 |
476 | static 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 |
483 | static int *const v3_data_procflags[] = {
484 | &hf_tcpclv3_data_procflags_start,
485 | &hf_tcpclv3_data_procflags_end,
486 | NULL((void*)0)
487 | };
488 | static int *const v4_chdr_flags[] = {
489 | &hf_tcpclv4_chdr_flags_cantls,
490 | NULL((void*)0)
491 | };
492 | static int *const v4_sess_term_flags[] = {
493 | &hf_tcpclv4_sess_term_flags_reply,
494 | NULL((void*)0)
495 | };
496 | static int *const v4_xfer_flags[] = {
497 | &hf_tcpclv4_xfer_flags_start,
498 | &hf_tcpclv4_xfer_flags_end,
499 | NULL((void*)0)
500 | };
501 | static int *const v4_sessext_flags[] = {
502 | &hf_tcpclv4_sessext_flags_crit,
503 | NULL((void*)0)
504 | };
505 | static int *const v4_xferext_flags[] = {
506 | &hf_tcpclv4_xferext_flags_crit,
507 | NULL((void*)0)
508 | };
509 |
510 | /* Tree Node Variables */
511 | static int ett_proto_tcpcl;
512 | static int ett_chdr;
513 | static int ett_tcpclv3_chdr_flags;
514 | static int ett_tcpclv3_mhdr;
515 | static int ett_tcpclv3_data_procflags;
516 | static int ett_tcpclv3_shutdown_flags;
517 | static int ett_xfer_segment;
518 | static int ett_xfer_segments;
519 | static int ett_tcpclv4_chdr_flags;
520 | static int ett_tcpclv4_mhdr;
521 | static int ett_tcpclv4_sess_term_flags;
522 | static int ett_tcpclv4_xfer_flags;
523 | static int ett_tcpclv4_sessext;
524 | static int ett_tcpclv4_sessext_flags;
525 | static int ett_tcpclv4_sessext_data;
526 | static int ett_tcpclv4_xferext;
527 | static int ett_tcpclv4_xferext_flags;
528 | static int ett_tcpclv4_xferext_data;
529 |
530 | static 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 |
551 | static expert_field ei_invalid_magic;
552 | static expert_field ei_invalid_version;
553 | static expert_field ei_mismatch_version;
554 | static expert_field ei_chdr_duplicate;
555 | static expert_field ei_length_clamped;
556 | static expert_field ei_chdr_missing;
557 |
558 | static expert_field ei_tcpclv3_eid_length;
559 | static expert_field ei_tcpclv3_invalid_msg_type;
560 | static expert_field ei_tcpclv3_data_flags;
561 | static expert_field ei_tcpclv3_segment_length;
562 | static expert_field ei_tcpclv3_ack_length;
563 |
564 | static expert_field ei_tcpclv4_invalid_msg_type;
565 | static expert_field ei_tcpclv4_invalid_sessext_type;
566 | static expert_field ei_tcpclv4_invalid_xferext_type;
567 | static expert_field ei_tcpclv4_extitem_critical;
568 | static expert_field ei_tcpclv4_sess_init_missing;
569 | static expert_field ei_tcpclv4_sess_init_duplicate;
570 | static expert_field ei_tcpclv4_sess_term_duplicate;
571 | static expert_field ei_tcpclv4_sess_term_reply_flag;
572 | static expert_field ei_tcpclv4_xfer_seg_over_seg_mru;
573 | static expert_field ei_tcpclv4_xfer_seg_missing_start;
574 | static expert_field ei_tcpclv4_xfer_seg_duplicate_start;
575 | static expert_field ei_tcpclv4_xfer_seg_missing_end;
576 | static expert_field ei_tcpclv4_xfer_seg_duplicate_end;
577 | static expert_field ei_tcpclv4_xfer_seg_no_relation;
578 | static expert_field ei_xfer_seg_over_total_len;
579 | static expert_field ei_xfer_mismatch_total_len;
580 | static expert_field ei_xfer_ack_mismatch_flags;
581 | static expert_field ei_xfer_ack_no_relation;
582 | static expert_field ei_tcpclv4_xfer_refuse_no_transfer;
583 | static expert_field ei_tcpclv4_xferload_over_xfer_mru;
584 |
585 | static ei_register_info ei_tcpcl[] = {
586 | {&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)}}}},
587 | {&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)}}}},
588 | {&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)}}}},
589 | {&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)}}}},
590 | {&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)}}}},
591 | {&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)}}}},
592 |
593 | {&ei_tcpclv3_eid_length, { "tcpcl.eid_length_invalid", PI_PROTOCOL0x09000000, PI_ERROR0x00800000, "Invalid EID Length", 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_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)}}}},
595 | {&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)}} }},
596 | {&ei_tcpclv3_segment_length, { "tcpcl.data.length.invalid", PI_PROTOCOL0x09000000, PI_ERROR0x00800000, "Invalid Data Length", 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_tcpclv3_ack_length, { "tcpcl.ack.length.error", PI_PROTOCOL0x09000000, PI_WARN0x00600000, "Ack Length: Error", 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 |
599 | {&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)}}}},
600 | {&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)}}}},
601 | {&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)}}}},
602 | {&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)}}}},
603 | {&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)}}}},
604 | {&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)}}}},
605 | {&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)}}}},
606 | {&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)}}}},
607 | {&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)}}}},
608 | {&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)}}}},
609 | {&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)}}}},
610 | {&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)}}}},
611 | {&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)}}}},
612 | {&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)}}}},
613 | {&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)}}}},
614 | {&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)}}}},
615 | {&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)}}}},
616 | {&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)}}}},
617 | {&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)}}}},
618 | {&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)}}}},
619 | };
620 |
621 | static const fragment_items xfer_frag_items = {
622 | /*Fragment subtrees*/
623 | &ett_xfer_segment,
624 | &ett_xfer_segments,
625 | /*Fragment Fields*/
626 | &hf_xfer_segments,
627 | &hf_xfer_segment,
628 | &hf_xfer_segment_overlap,
629 | &hf_xfer_segment_overlap_conflicts,
630 | &hf_xfer_segment_multiple_tails,
631 | &hf_xfer_segment_too_long_fragment,
632 | &hf_xfer_segment_error,
633 | &hf_xfer_segment_count,
634 | /*Reassembled in field*/
635 | &hf_xfer_reassembled_in,
636 | /*Reassembled length field*/
637 | &hf_xfer_reassembled_length,
638 | /* Reassembled data field */
639 | &hf_xfer_reassembled_data,
640 | /*Tag*/
641 | "Transfer segments"
642 | };
643 |
644 | static unsigned tvb_get_sdnv(tvbuff_t *tvb, unsigned offset, uint64_t *value) {
645 | return tvb_get_varint(tvb, offset, FT_VARINT_MAX_LEN10, value, ENC_VARINT_SDNV0x00000010);
646 | }
647 |
648 | static void tcpcl_frame_loc_init(tcpcl_frame_loc_t *loc, const packet_info *pinfo, tvbuff_t *tvb, const int offset) {
649 | loc->frame_num = pinfo->num;
650 |
651 | loc->ds_idx = get_data_source_index_by_tvb(pinfo, tvb_get_ds_tvb(tvb));
652 | 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" , 652, "loc->ds_idx >= 0"))));
653 | loc->raw_offset = tvb_raw_offset(tvb) + offset;
654 | DISSECTOR_ASSERT(offset >= 0)((void) ((offset >= 0) ? (void)0 : (proto_report_dissector_bug ("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-tcpcl.c" , 654, "offset >= 0"))));
655 | }
656 |
657 | /** Construct a new object on the file allocator.
658 | */
659 | static tcpcl_frame_loc_t * tcpcl_frame_loc_new(wmem_allocator_t *alloc, const packet_info *pinfo, tvbuff_t *tvb, const int offset) {
660 | tcpcl_frame_loc_t *obj = wmem_new(alloc, tcpcl_frame_loc_t)((tcpcl_frame_loc_t*)wmem_alloc((alloc), sizeof(tcpcl_frame_loc_t )));
661 | tcpcl_frame_loc_init(obj, pinfo, tvb, offset);
662 | return obj;
663 | }
664 |
665 | /** Construct a new object on the file allocator.
666 | */
667 | static tcpcl_frame_loc_t * tcpcl_frame_loc_clone(wmem_allocator_t *alloc, const tcpcl_frame_loc_t *loc) {
668 | tcpcl_frame_loc_t *obj = wmem_new(alloc, tcpcl_frame_loc_t)((tcpcl_frame_loc_t*)wmem_alloc((alloc), sizeof(tcpcl_frame_loc_t )));
669 | *obj = *loc;
670 | return obj;
671 | }
672 |
673 | #define tcpcl_frame_loc_freewmem_free wmem_free
674 |
675 | /** Function to match the GCompareDataFunc signature.
676 | */
677 | static int tcpcl_frame_loc_compare(const void *a, const void *b, void *user_data _U___attribute__((unused))) {
678 | const tcpcl_frame_loc_t *aloc = a;
679 | const tcpcl_frame_loc_t *bloc = b;
680 |
681 | if (aloc->frame_num < bloc->frame_num) {
682 | return -1;
683 | }
684 | else if (aloc->frame_num > bloc->frame_num) {
685 | return 1;
686 | }
687 |
688 | if (aloc->ds_idx < bloc->ds_idx) {
689 | return -1;
690 | }
691 | else if (aloc->ds_idx > bloc->ds_idx) {
692 | return 1;
693 | }
694 | if (aloc->raw_offset < bloc->raw_offset) {
695 | return -1;
696 | }
697 | else if (aloc->raw_offset > bloc->raw_offset) {
698 | return 1;
699 | }
700 | return 0;
701 | }
702 |
703 | /** Function to match the GCompareFunc signature.
704 | */
705 | static gboolean tcpcl_frame_loc_equal(const void *a, const void *b) {
706 | const tcpcl_frame_loc_t *aobj = a;
707 | const tcpcl_frame_loc_t *bobj = b;
708 | return (
709 | (aobj->frame_num == bobj->frame_num)
710 | && (aobj->ds_idx == bobj->ds_idx)
711 | && (aobj->raw_offset == bobj->raw_offset)
712 | );
713 | }
714 |
715 | /** Function to match the GHashFunc signature.
716 | */
717 | static unsigned tcpcl_frame_loc_hash(const void *key) {
718 | const tcpcl_frame_loc_t *obj = key;
719 | return (
720 | g_int_hash(&(obj->frame_num))
721 | ^ g_int_hash(&(obj->ds_idx))
722 | ^ g_int_hash(&(obj->raw_offset))
723 | );
724 | }
725 |
726 | struct tcpcl_ack_meta;
727 | typedef struct tcpcl_ack_meta tcpcl_ack_meta_t;
728 | struct tcpcl_seg_meta;
729 | typedef struct tcpcl_seg_meta tcpcl_seg_meta_t;
730 |
731 | struct tcpcl_seg_meta {
732 | /// Location associated with this metadata
733 | tcpcl_frame_loc_t frame_loc;
734 | /// Timestamp on the frame (end time if reassembled)
735 | nstime_t frame_time;
736 | /// Copy of message flags
737 | uint8_t flags;
738 | /// Total transfer length including this segment
739 | uint64_t seen_len;
740 |
741 | /// Potential related start segment
742 | tcpcl_seg_meta_t *related_start;
743 | /// Potential related XFER_ACK
744 | tcpcl_ack_meta_t *related_ack;
745 | };
746 |
747 | static tcpcl_seg_meta_t * tcpcl_seg_meta_new(const packet_info *pinfo, const tcpcl_frame_loc_t *loc) {
748 | 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 )));
749 | obj->frame_loc = *loc;
750 | obj->frame_time = pinfo->abs_ts;
751 | obj->flags = 0;
752 | obj->seen_len = 0;
753 | obj->related_start = NULL((void*)0);
754 | obj->related_ack = NULL((void*)0);
755 | return obj;
756 | }
757 |
758 | static void tcpcl_seg_meta_free(tcpcl_seg_meta_t *obj) {
759 | wmem_free(wmem_file_scope(), obj);
760 | }
761 |
762 | /** Function to match the GCompareFunc signature.
763 | */
764 | static int tcpcl_seg_meta_compare_loc(const void *a, const void *b) {
765 | return tcpcl_frame_loc_compare(
766 | &(((tcpcl_seg_meta_t *)a)->frame_loc),
767 | &(((tcpcl_seg_meta_t *)b)->frame_loc),
768 | NULL((void*)0)
769 | );
770 | }
771 |
772 | struct tcpcl_ack_meta {
773 | /// Location associated with this metadata
774 | tcpcl_frame_loc_t frame_loc;
775 | /// Timestamp on the frame (end time if reassembled)
776 | nstime_t frame_time;
777 | /// Copy of message flags
778 | uint8_t flags;
779 | /// Total acknowledged length including this ack
780 | uint64_t seen_len;
781 |
782 | /// Potential related start segment
783 | tcpcl_seg_meta_t *related_start;
784 | /// Potential related XFER_SEGMENT
785 | tcpcl_seg_meta_t *related_seg;
786 | };
787 |
788 | static tcpcl_ack_meta_t * tcpcl_ack_meta_new(const packet_info *pinfo, const tcpcl_frame_loc_t *loc) {
789 | 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 )));
790 | obj->frame_loc = *loc;
791 | obj->frame_time = pinfo->abs_ts;
792 | obj->flags = 0;
793 | obj->seen_len = 0;
794 | obj->related_start = NULL((void*)0);
795 | obj->related_seg = NULL((void*)0);
796 | return obj;
797 | }
798 |
799 | static void tcpcl_ack_meta_free(tcpcl_ack_meta_t *obj) {
800 | wmem_free(wmem_file_scope(), obj);
801 | }
802 |
803 | /** Function to match the GCompareFunc signature.
804 | */
805 | static int tcpcl_ack_meta_compare_loc(const void *a, const void *b) {
806 | return tcpcl_frame_loc_compare(
807 | &(((tcpcl_seg_meta_t *)a)->frame_loc),
808 | &(((tcpcl_seg_meta_t *)b)->frame_loc),
809 | NULL((void*)0)
810 | );
811 | }
812 |
813 | static tcpcl_transfer_t * tcpcl_transfer_new(void) {
814 | tcpcl_transfer_t *obj = wmem_new(wmem_file_scope(), tcpcl_transfer_t)((tcpcl_transfer_t*)wmem_alloc((wmem_file_scope()), sizeof(tcpcl_transfer_t )));
815 | obj->seg_list = wmem_list_new(wmem_file_scope());
816 | obj->ack_list = wmem_list_new(wmem_file_scope());
817 | obj->total_length = NULL((void*)0);
818 | return obj;
819 | }
820 |
821 | static tcpcl_transfer_t * get_or_create_transfer_t(wmem_map_t *table, const uint64_t xfer_id) {
822 | tcpcl_transfer_t *xfer = wmem_map_lookup(table, &xfer_id);
823 | if (!xfer) {
824 | uint64_t *key = wmem_new(wmem_file_scope(), uint64_t)((uint64_t*)wmem_alloc((wmem_file_scope()), sizeof(uint64_t)) );
825 | *key = xfer_id;
826 | xfer = tcpcl_transfer_new();
827 | wmem_map_insert(table, key, xfer);
828 | }
829 | return xfer;
830 | }
831 |
832 | static tcpcl_peer_t * tcpcl_peer_new(void) {
833 | tcpcl_peer_t *obj = wmem_new0(wmem_file_scope(), tcpcl_peer_t)((tcpcl_peer_t*)wmem_alloc0((wmem_file_scope()), sizeof(tcpcl_peer_t )));
834 | clear_address(&(obj->addr));
835 | obj->frame_loc_to_transfer = wmem_map_new(wmem_file_scope(), tcpcl_frame_loc_hash, tcpcl_frame_loc_equal);
836 | obj->transfers = wmem_map_new(wmem_file_scope(), g_int64_hash, g_int64_equal);
837 | return obj;
838 | }
839 |
840 | static void tcpcl_peer_associate_transfer(tcpcl_peer_t *peer, const tcpcl_frame_loc_t *loc, const uint64_t xfer_id) {
841 | void * *xfer = wmem_map_lookup(peer->frame_loc_to_transfer, loc);
842 | if (!xfer) {
843 | tcpcl_frame_loc_t *key = tcpcl_frame_loc_clone(wmem_file_scope(), loc);
844 | uint64_t *val = wmem_new(wmem_file_scope(), uint64_t)((uint64_t*)wmem_alloc((wmem_file_scope()), sizeof(uint64_t)) );
845 | *val = xfer_id;
846 | wmem_map_insert(peer->frame_loc_to_transfer, key, val);
847 | }
848 | }
849 |
850 | static tcpcl_conversation_t * tcpcl_conversation_new(void) {
851 | tcpcl_conversation_t *obj = wmem_new0(wmem_file_scope(), tcpcl_conversation_t)((tcpcl_conversation_t*)wmem_alloc0((wmem_file_scope()), sizeof (tcpcl_conversation_t)));
852 | obj->active = tcpcl_peer_new();
853 | obj->passive = tcpcl_peer_new();
854 | return obj;
855 | }
856 |
857 | tcpcl_dissect_ctx_t * tcpcl_dissect_ctx_get(tvbuff_t *tvb, packet_info *pinfo, const int offset) {
858 | conversation_t *convo = find_or_create_conversation(pinfo);
859 | tcpcl_conversation_t *tcpcl_convo = (tcpcl_conversation_t *)conversation_get_proto_data(convo, proto_tcpcl);
860 | if (!tcpcl_convo) {
861 | return NULL((void*)0);
862 | }
863 |
864 | 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 )));
865 | ctx->convo = tcpcl_convo;
866 | ctx->cur_loc = tcpcl_frame_loc_new(pinfo->pool, pinfo, tvb, offset);
867 |
868 | const bool_Bool src_is_active = (
869 | addresses_equal(&(ctx->convo->active->addr), &(pinfo->src))
870 | && (ctx->convo->active->port == pinfo->srcport)
871 | );
872 | if (src_is_active) {
873 | ctx->tx_peer = ctx->convo->active;
874 | ctx->rx_peer = ctx->convo->passive;
875 | }
876 | else {
877 | ctx->tx_peer = ctx->convo->passive;
878 | ctx->rx_peer = ctx->convo->active;
879 | }
880 |
881 | ctx->is_contact = (
882 | !(ctx->tx_peer->chdr_missing)
883 | && (
884 | !(ctx->tx_peer->chdr_seen)
885 | || tcpcl_frame_loc_equal(ctx->tx_peer->chdr_seen, ctx->cur_loc)
886 | )
887 | );
888 |
889 | return ctx;
890 | }
891 |
892 | static void set_chdr_missing(tcpcl_peer_t *peer, uint8_t version) {
893 | peer->chdr_missing = true1;
894 | peer->version = version;
895 | // assumed parameters
896 | peer->segment_mru = UINT64_MAX(18446744073709551615UL);
897 | peer->transfer_mru = UINT64_MAX(18446744073709551615UL);
898 | }
899 |
900 |
901 | static void try_negotiate(tcpcl_dissect_ctx_t *ctx, packet_info *pinfo) {
902 | if (!(ctx->convo->contact_negotiated)
903 | && (ctx->convo->active->chdr_seen)
904 | && (ctx->convo->passive->chdr_seen)) {
905 | ctx->convo->session_use_tls = (
906 | ctx->convo->active->can_tls & ctx->convo->passive->can_tls
907 | );
908 | ctx->convo->contact_negotiated = true1;
909 |
910 | if (ctx->convo->session_use_tls
911 | && (!(ctx->convo->session_tls_start))) {
912 | col_append_str(pinfo->cinfo, COL_INFO, " [STARTTLS]");
913 | ctx->convo->session_tls_start = tcpcl_frame_loc_clone(wmem_file_scope(), ctx->cur_loc);
914 | ssl_starttls_ack(tls_handle, pinfo, tcpcl_handle);
915 | }
916 | }
917 |
918 | if (!(ctx->convo->sess_negotiated)
919 | && (ctx->convo->active->sess_init_seen)
920 | && (ctx->convo->passive->sess_init_seen)) {
921 | ctx->convo->sess_keepalive = MIN((((ctx->convo->active->keepalive) < (ctx->convo ->passive->keepalive)) ? (ctx->convo->active-> keepalive) : (ctx->convo->passive->keepalive))
922 | ctx->convo->active->keepalive,(((ctx->convo->active->keepalive) < (ctx->convo ->passive->keepalive)) ? (ctx->convo->active-> keepalive) : (ctx->convo->passive->keepalive))
923 | ctx->convo->passive->keepalive(((ctx->convo->active->keepalive) < (ctx->convo ->passive->keepalive)) ? (ctx->convo->active-> keepalive) : (ctx->convo->passive->keepalive))
924 | )(((ctx->convo->active->keepalive) < (ctx->convo ->passive->keepalive)) ? (ctx->convo->active-> keepalive) : (ctx->convo->passive->keepalive));
925 | ctx->convo->sess_negotiated = true1;
926 |
927 | }
928 | }
929 |
930 | typedef struct {
931 | // key type for addresses_ports_reassembly_table_functions
932 | void *addr_port;
933 | // TCPCL ID
934 | uint64_t xfer_id;
935 | } tcpcl_fragment_key_t;
936 |
937 | static unsigned fragment_key_hash(const void *ptr) {
938 | const tcpcl_fragment_key_t *obj = (const tcpcl_fragment_key_t *)ptr;
939 | return (
940 | addresses_ports_reassembly_table_functions.hash_func(obj->addr_port)
941 | ^ g_int64_hash(&(obj->xfer_id))
942 | );
943 | }
944 |
945 | static gboolean fragment_key_equal(const void *ptrA, const void *ptrB) {
946 | const tcpcl_fragment_key_t *objA = (const tcpcl_fragment_key_t *)ptrA;
947 | const tcpcl_fragment_key_t *objB = (const tcpcl_fragment_key_t *)ptrB;
948 | return (
949 | addresses_ports_reassembly_table_functions.equal_func(objA->addr_port, objB->addr_port)
950 | && (objA->xfer_id == objB->xfer_id)
951 | );
952 | }
953 |
954 | static void *fragment_key_temporary(const packet_info *pinfo, const uint32_t id, const void *data) {
955 | 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)));
956 | obj->addr_port = addresses_ports_reassembly_table_functions.temporary_key_func(pinfo, id, NULL((void*)0));
957 | obj->xfer_id = *((const uint64_t *)data);
958 | return (void *)obj;
959 | }
960 |
961 | static void *fragment_key_persistent(const packet_info *pinfo, const uint32_t id, const void *data) {
962 | 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)));
963 | obj->addr_port = addresses_ports_reassembly_table_functions.persistent_key_func(pinfo, id, NULL((void*)0));
964 | obj->xfer_id = *((const uint64_t *)data);
965 | return (void *)obj;
966 | }
967 |
968 | static void fragment_key_free_temporary(void *ptr) {
969 | tcpcl_fragment_key_t *obj = (tcpcl_fragment_key_t *)ptr;
970 | if (obj) {
971 | addresses_ports_reassembly_table_functions.free_temporary_key_func(obj->addr_port);
972 | 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);
973 | }
974 | }
975 |
976 | static void fragment_key_free_persistent(void *ptr) {
977 | tcpcl_fragment_key_t *obj = (tcpcl_fragment_key_t *)ptr;
978 | if (obj) {
979 | addresses_ports_reassembly_table_functions.free_persistent_key_func(obj->addr_port);
980 | 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);
981 | }
982 | }
983 |
984 | static reassembly_table_functions xfer_reassembly_table_functions = {
985 | fragment_key_hash,
986 | fragment_key_equal,
987 | fragment_key_temporary,
988 | fragment_key_persistent,
989 | fragment_key_free_temporary,
990 | fragment_key_free_persistent
991 | };
992 |
993 | /** Record metadata about one segment in a transfer.
994 | */
995 | static void transfer_add_segment(tcpcl_dissect_ctx_t *ctx, uint64_t xfer_id, uint8_t flags,
996 | uint64_t data_len,
997 | packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree_msg,
998 | proto_item *item_msg, proto_item *item_flags) {
999 | tcpcl_transfer_t *xfer = get_or_create_transfer_t(ctx->tx_peer->transfers, xfer_id);
1000 |
1001 | uint8_t flag_start, flag_end;
1002 | if (ctx->tx_peer->version == 3) {
1003 | flag_start = TCPCLV3_DATA_START_FLAG;
1004 | flag_end = TCPCLV3_DATA_END_FLAG;
1005 | }
1006 | else {
1007 | flag_start = TCPCLV4_TRANSFER_FLAG_START;
1008 | flag_end = TCPCLV4_TRANSFER_FLAG_END;
1009 | }
1010 |
1011 | // Add or get the segment metadata
1012 | tcpcl_seg_meta_t *seg_meta = tcpcl_seg_meta_new(pinfo, ctx->cur_loc);
1013 | wmem_list_frame_t *frm = wmem_list_find_custom(xfer->seg_list, seg_meta, tcpcl_seg_meta_compare_loc);
1014 | if (frm) {
1015 | tcpcl_seg_meta_free(seg_meta);
1016 | seg_meta = wmem_list_frame_data(frm);
1017 | }
1018 | else {
1019 | wmem_list_append(xfer->seg_list, seg_meta);
1020 | frm = wmem_list_tail(xfer->seg_list);
1021 | // Set for new item
1022 | seg_meta->flags = flags;
1023 | }
1024 |
1025 | // mark start-of-transfer
1026 | if (!(seg_meta->related_start)) {
1027 | wmem_list_frame_t *frm_front = wmem_list_head(xfer->seg_list);
1028 | tcpcl_seg_meta_t *seg_front = frm_front ? wmem_list_frame_data(frm_front) : NULL((void*)0);
1029 | if (seg_front && (seg_front->flags & flag_start)) {
1030 | seg_meta->related_start = seg_front;
1031 | }
1032 | }
1033 |
1034 | // accumulate segment sizes
1035 | uint64_t prev_seen_len;
1036 | wmem_list_frame_t *frm_prev = wmem_list_frame_prev(frm);
1037 | if (!frm_prev) {
1038 | if (!(flags & flag_start)) {
1039 | expert_add_info(pinfo, item_flags, &ei_tcpclv4_xfer_seg_missing_start);
1040 | }
1041 | prev_seen_len = 0;
1042 | }
1043 | else {
1044 | const tcpcl_seg_meta_t *seg_prev = wmem_list_frame_data(frm_prev);
1045 | if (flags & flag_start) {
1046 | expert_add_info(pinfo, item_flags, &ei_tcpclv4_xfer_seg_duplicate_start);
1047 | }
1048 | prev_seen_len = seg_prev->seen_len;
1049 | }
1050 | wmem_list_frame_t *frm_next = wmem_list_frame_next(frm);
1051 | if (!frm_next) {
1052 | if (!(flags & flag_end)) {
1053 | expert_add_info(pinfo, item_flags, &ei_tcpclv4_xfer_seg_missing_end);
1054 | }
1055 | }
1056 | else {
1057 | if (flags & flag_end) {
1058 | expert_add_info(pinfo, item_flags, &ei_tcpclv4_xfer_seg_duplicate_end);
1059 | }
1060 | }
1061 | seg_meta->seen_len = prev_seen_len + data_len;
1062 |
1063 | proto_item *item_seen = proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_segment_seen_len, tvb, 0, 0, seg_meta->seen_len);
1064 | proto_item_set_generated(item_seen);
1065 | if (seg_meta->seen_len > ctx->rx_peer->transfer_mru) {
1066 | expert_add_info(pinfo, item_seen, &ei_tcpclv4_xferload_over_xfer_mru);
1067 | }
1068 | if (xfer->total_length) {
1069 | if (seg_meta->seen_len > *(xfer->total_length)) {
1070 | expert_add_info(pinfo, item_seen, &ei_xfer_seg_over_total_len);
1071 | }
1072 | else if ((flags & flag_end)
1073 | && (seg_meta->seen_len != *(xfer->total_length))) {
1074 | expert_add_info(pinfo, item_seen, &ei_xfer_mismatch_total_len);
1075 | }
1076 | proto_item *item_total = proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_total_len, tvb, 0, 0, *(xfer->total_length));
1077 | proto_item_set_generated(item_total);
1078 | }
1079 |
1080 | if (seg_meta->related_ack) {
1081 | 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);
1082 | proto_item_set_generated(item_rel);
1083 |
1084 | nstime_t td;
1085 | nstime_delta(&td, &(seg_meta->related_ack->frame_time), &(seg_meta->frame_time));
1086 | proto_item *item_td = proto_tree_add_time(tree_msg, hf_tcpclv4_xfer_segment_time_diff, tvb, 0, 0, &td);
1087 | proto_item_set_generated(item_td);
1088 |
1089 | }
1090 | else {
1091 | expert_add_info(pinfo, item_msg, &ei_tcpclv4_xfer_seg_no_relation);
1092 | }
1093 | if (seg_meta->related_start && (seg_meta->related_start != seg_meta)) {
1094 | 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);
1095 | proto_item_set_generated(item_rel);
1096 |
1097 | nstime_t td;
1098 | nstime_delta(&td, &(seg_meta->frame_time), &(seg_meta->related_start->frame_time));
1099 | proto_item *item_td = proto_tree_add_time(tree_msg, hf_tcpclv4_xfer_segment_time_start, tvb, 0, 0, &td);
1100 | proto_item_set_generated(item_td);
1101 | }
1102 | }
1103 |
1104 | static void transfer_add_ack(tcpcl_dissect_ctx_t *ctx, uint64_t xfer_id, uint8_t flags,
1105 | uint64_t ack_len,
1106 | packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree_msg,
1107 | proto_item *item_msg, proto_item *item_flags) {
1108 | tcpcl_transfer_t *xfer = get_or_create_transfer_t(ctx->rx_peer->transfers, xfer_id);
1109 |
1110 | // Add or get the ack metadata
1111 | tcpcl_ack_meta_t *ack_meta = tcpcl_ack_meta_new(pinfo, ctx->cur_loc);
1112 | wmem_list_frame_t *frm = wmem_list_find_custom(xfer->ack_list, ack_meta, tcpcl_ack_meta_compare_loc);
1113 | if (frm) {
1114 | tcpcl_ack_meta_free(ack_meta);
1115 | ack_meta = wmem_list_frame_data(frm);
1116 | }
1117 | else {
1118 | wmem_list_append(xfer->ack_list, ack_meta);
1119 | frm = wmem_list_tail(xfer->ack_list);
| Value stored to 'frm' is never read
1120 | // Set for new item
1121 | ack_meta->flags = flags;
1122 | ack_meta->seen_len = ack_len;
1123 | }
1124 |
1125 | // mark start-of-transfer
1126 | if (!(ack_meta->related_start)) {
1127 | wmem_list_frame_t *frm_front = wmem_list_head(xfer->seg_list);
1128 | tcpcl_seg_meta_t *seg_front = frm_front ? wmem_list_frame_data(frm_front) : NULL((void*)0);
1129 | if (seg_front && (seg_front->flags & TCPCLV4_TRANSFER_FLAG_START)) {
1130 | ack_meta->related_start = seg_front;
1131 | }
1132 | }
1133 |
1134 | // Assemble both of the links here, as ACK will always follow segment
1135 | if (!(ack_meta->related_seg)) {
1136 | wmem_list_frame_t *seg_iter = wmem_list_head(xfer->seg_list);
1137 | for (; seg_iter; seg_iter = wmem_list_frame_next(seg_iter)) {
1138 | tcpcl_seg_meta_t *seg_meta = wmem_list_frame_data(seg_iter);
1139 | if (seg_meta->seen_len == ack_meta->seen_len) {
1140 | seg_meta->related_ack = ack_meta;
1141 | ack_meta->related_seg = seg_meta;
1142 | }
1143 | }
1144 | }
1145 |
1146 | if (xfer->total_length) {
1147 | proto_item *item_total = proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_total_len, tvb, 0, 0, *(xfer->total_length));
1148 | proto_item_set_generated(item_total);
1149 | }
1150 | if (ack_meta->related_seg) {
1151 | 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);
1152 | proto_item_set_generated(item_rel);
1153 |
1154 | nstime_t td;
1155 | nstime_delta(&td, &(ack_meta->frame_time), &(ack_meta->related_seg->frame_time));
1156 | proto_item *item_td = proto_tree_add_time(tree_msg, hf_tcpclv4_xfer_ack_time_diff, tvb, 0, 0, &td);
1157 | proto_item_set_generated(item_td);
1158 |
1159 | if (item_flags && (ack_meta->flags != ack_meta->related_seg->flags)) {
1160 | expert_add_info(pinfo, item_flags, &ei_xfer_ack_mismatch_flags);
1161 | }
1162 | }
1163 | else {
1164 | expert_add_info(pinfo, item_msg, &ei_xfer_ack_no_relation);
1165 | }
1166 | if (ack_meta->related_start) {
1167 | 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);
1168 | proto_item_set_generated(item_rel);
1169 |
1170 | nstime_t td;
1171 | nstime_delta(&td, &(ack_meta->frame_time), &(ack_meta->related_start->frame_time));
1172 | proto_item *item_td = proto_tree_add_time(tree_msg, hf_tcpclv4_xfer_ack_time_start, tvb, 0, 0, &td);
1173 | proto_item_set_generated(item_td);
1174 | }
1175 | }
1176 |
1177 | static void transfer_add_refuse(tcpcl_dissect_ctx_t *ctx, uint64_t xfer_id,
1178 | packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree_msg,
1179 | proto_item *item_msg) {
1180 | const tcpcl_transfer_t *xfer = wmem_map_lookup(ctx->rx_peer->transfers, &xfer_id);
1181 | const tcpcl_seg_meta_t *seg_last = NULL((void*)0);
1182 | if (xfer) {
1183 | wmem_list_frame_t *seg_iter = wmem_list_tail(xfer->seg_list);
1184 | seg_iter = seg_iter ? wmem_list_frame_prev(seg_iter) : NULL((void*)0);
1185 | seg_last = seg_iter ? wmem_list_frame_data(seg_iter) : NULL((void*)0);
1186 | }
1187 |
1188 | if (seg_last) {
1189 | 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);
1190 | proto_item_set_generated(item_rel);
1191 | }
1192 | else {
1193 | expert_add_info(pinfo, item_msg, &ei_tcpclv4_xfer_refuse_no_transfer);
1194 | }
1195 | }
1196 |
1197 | static int get_clamped_length(uint64_t orig, packet_info *pinfo, proto_item *item) {
1198 | int clamped;
1199 | if (orig > INT_MAX2147483647) {
1200 | clamped = INT_MAX2147483647;
1201 | if (pinfo && item) {
1202 | expert_add_info(pinfo, item, &ei_length_clamped);
1203 | }
1204 | }
1205 | else {
1206 | clamped = (int) orig;
1207 | }
1208 | return clamped;
1209 | }
1210 |
1211 | static unsigned
1212 | get_v3_msg_len(packet_info *pinfo _U___attribute__((unused)), tvbuff_t *tvb, int offset,
1213 | tcpcl_dissect_ctx_t *ctx _U___attribute__((unused)))
1214 | {
1215 | uint64_t len;
1216 | unsigned bytecount;
1217 | uint8_t conv_hdr = tvb_get_uint8(tvb, offset);
1218 | offset += 1;
1219 | unsigned msg_len = 1;
1220 |
1221 | switch (conv_hdr & TCPCLV3_TYPE_MASK)
1222 | {
1223 | case TCPCLV3_DATA_SEGMENT: {
1224 | /* get length from sdnv */
1225 | bytecount = tvb_get_sdnv(tvb, offset, &len);
1226 | if (bytecount == 0) {
1227 | return 0;
1228 | }
1229 | const int len_clamp = get_clamped_length(len, NULL((void*)0), NULL((void*)0));
1230 | msg_len += bytecount + (unsigned)len_clamp;
1231 | break;
1232 | }
1233 | case TCPCLV3_ACK_SEGMENT:
1234 | /* get length from sdnv */
1235 | bytecount = tvb_get_sdnv(tvb, offset, &len);
1236 | if (bytecount == 0) {
1237 | return 0;
1238 | }
1239 | msg_len += bytecount;
1240 | break;
1241 |
1242 | case TCPCLV3_KEEP_ALIVE:
1243 | case TCPCLV3_REFUSE_BUNDLE:
1244 | /* always 1 byte */
1245 | break;
1246 | case TCPCLV3_SHUTDOWN:
1247 | if (conv_hdr & TCPCLV3_SHUTDOWN_REASON) {
1248 | msg_len += 1;
1249 | }
1250 | if (conv_hdr & TCPCLV3_SHUTDOWN_DELAY) {
1251 | msg_len += 2;
1252 | }
1253 | break;
1254 |
1255 | case TCPCLV3_LENGTH:
1256 | /* get length from sdnv */
1257 | bytecount = tvb_get_sdnv(tvb, offset, &len);
1258 | if (bytecount == 0) {
1259 | return 0;
1260 | }
1261 | msg_len += bytecount;
1262 | break;
1263 |
1264 | default:
1265 | // no known message
1266 | return 0;
1267 | }
1268 |
1269 | return msg_len;
1270 | }
1271 |
1272 | static int
1273 | dissect_v3_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1274 | tcpcl_dissect_ctx_t *ctx)
1275 | {
1276 | uint8_t conv_hdr;
1277 | const char *msgtype_name;
1278 | uint8_t refuse_bundle_hdr;
1279 | int offset = 0;
1280 | int sdnv_length;
1281 | uint64_t segment_length;
1282 | proto_item *conv_item, *sub_item;
1283 | proto_tree *conv_tree, *sub_tree;
1284 | uint64_t *xfer_id = NULL((void*)0);
1285 | proto_item *item_xfer_id = NULL((void*)0);
1286 |
1287 | conv_item = proto_tree_add_item(tree, hf_tcpclv3_mhdr, tvb, 0, -1, ENC_NA0x00000000);
1288 | conv_tree = proto_item_add_subtree(conv_item, ett_tcpclv3_mhdr);
1289 |
1290 | conv_hdr = tvb_get_uint8(tvb, offset);
1291 | proto_tree_add_item(conv_tree, hf_tcpclv3_pkt_type, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
1292 |
1293 | msgtype_name = val_to_str_const((conv_hdr>>4)&0xF, v3_message_type_vals, "Unknown");
1294 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), msgtype_name);
1295 | proto_item_append_text(proto_tree_get_parent(conv_tree), ": %s", msgtype_name);
1296 |
1297 | switch (conv_hdr & TCPCLV3_TYPE_MASK) {
1298 | case TCPCLV3_DATA_SEGMENT: {
1299 | proto_item *item_flags;
1300 |
1301 | item_flags = proto_tree_add_bitmask(
1302 | conv_tree, tvb,
1303 | offset, hf_tcpclv3_data_procflags,
1304 | ett_tcpclv3_data_procflags, v3_data_procflags,
1305 | ENC_BIG_ENDIAN0x00000000
1306 | );
1307 | offset += 1;
1308 |
1309 | /* Only Start and End flags (bits 0 & 1) are valid in Data Segment */
1310 | if ((conv_hdr & ~((uint8_t)TCPCLV3_TYPE_MASK | (uint8_t)TCPCLV3_DATA_FLAGS)) != 0) {
1311 | expert_add_info(pinfo, item_flags, &ei_tcpclv3_data_flags);
1312 | }
1313 |
1314 | 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);
1315 | if (sdnv_length == 0) {
1316 | expert_add_info(pinfo, sub_item, &ei_tcpclv3_segment_length);
1317 | return 0;
1318 | }
1319 | offset += sdnv_length;
1320 | const int data_len_clamp = get_clamped_length(segment_length, pinfo, sub_item);
1321 |
1322 | // implied transfer ID
1323 | xfer_id = wmem_map_lookup(ctx->tx_peer->frame_loc_to_transfer, ctx->cur_loc);
1324 | if (!xfer_id) {
1325 | xfer_id = wmem_new(pinfo->pool, uint64_t)((uint64_t*)wmem_alloc((pinfo->pool), sizeof(uint64_t)));
1326 | *xfer_id = wmem_map_size(ctx->tx_peer->transfers);
1327 |
1328 | if (conv_hdr & TCPCLV3_DATA_START_FLAG) {
1329 | *xfer_id += 1;
1330 | get_or_create_transfer_t(ctx->tx_peer->transfers, *xfer_id);
1331 | }
1332 | tcpcl_peer_associate_transfer(ctx->tx_peer, ctx->cur_loc, *xfer_id);
1333 | }
1334 | item_xfer_id = proto_tree_add_uint64(conv_tree, hf_tcpclv3_xfer_id, tvb, 0, 0, *xfer_id);
1335 | proto_item_set_generated(item_xfer_id);
1336 |
1337 | proto_tree_add_item(conv_tree, hf_tcpclv3_data_segment_data, tvb, offset, data_len_clamp, ENC_NA0x00000000);
1338 |
1339 | if (tcpcl_analyze_sequence) {
1340 | transfer_add_segment(ctx, *xfer_id, (conv_hdr & TCPCLV3_DATA_FLAGS), segment_length, pinfo, tvb, conv_tree, conv_item, item_flags);
1341 | }
1342 |
1343 | if (tcpcl_desegment_transfer) {
1344 | // Reassemble the segments
1345 | fragment_head *frag_msg;
1346 | frag_msg = fragment_add_seq_next(
1347 | &xfer_reassembly_table,
1348 | tvb, offset,
1349 | pinfo, 0, xfer_id,
1350 | data_len_clamp,
1351 | !(conv_hdr & TCPCLV3_DATA_END_FLAG)
1352 | );
1353 | ctx->xferload = process_reassembled_data(
1354 | tvb, offset, pinfo,
1355 | "Reassembled Transfer",
1356 | frag_msg,
1357 | &xfer_frag_items,
1358 | NULL((void*)0),
1359 | tree
1360 | );
1361 | }
1362 | offset += data_len_clamp;
1363 |
1364 | break;
1365 | }
1366 | case TCPCLV3_ACK_SEGMENT: {
1367 | /*No valid flags*/
1368 | offset += 1;
1369 |
1370 | sub_item = proto_tree_add_item_ret_varint(conv_tree, hf_tcpclv3_ack_length, tvb, offset, -1, ENC_VARINT_SDNV0x00000010, &segment_length, &sdnv_length);
1371 | if (sdnv_length == 0) {
1372 | expert_add_info(pinfo, sub_item, &ei_tcpclv3_ack_length);
1373 | } else {
1374 | offset += sdnv_length;
1375 | }
1376 |
1377 | // implied transfer ID
1378 | xfer_id = wmem_map_lookup(ctx->rx_peer->frame_loc_to_transfer, ctx->cur_loc);
1379 | if (!xfer_id) {
1380 | xfer_id = wmem_new(pinfo->pool, uint64_t)((uint64_t*)wmem_alloc((pinfo->pool), sizeof(uint64_t)));
1381 | *xfer_id = wmem_map_size(ctx->rx_peer->transfers);
1382 |
1383 | tcpcl_peer_associate_transfer(ctx->rx_peer, ctx->cur_loc, *xfer_id);
1384 | }
1385 | item_xfer_id = proto_tree_add_uint64(conv_tree, hf_tcpclv3_xfer_id, tvb, 0, 0, *xfer_id);
1386 | proto_item_set_generated(item_xfer_id);
1387 |
1388 | if (tcpcl_analyze_sequence) {
1389 | transfer_add_ack(ctx, *xfer_id, 0, segment_length, pinfo, tvb, conv_tree, conv_item, NULL((void*)0));
1390 | }
1391 |
1392 | break;
1393 | }
1394 | case TCPCLV3_KEEP_ALIVE:
1395 | /*No valid flags in Keep Alive*/
1396 | offset += 1;
1397 | break;
1398 |
1399 | case TCPCLV3_SHUTDOWN:
1400 | /* Add tree for Shutdown Flags */
1401 | sub_item = proto_tree_add_item(conv_tree, hf_tcpclv3_shutdown_flags, tvb,
1402 | offset, 1, ENC_BIG_ENDIAN0x00000000);
1403 | sub_tree = proto_item_add_subtree(sub_item, ett_tcpclv3_shutdown_flags);
1404 |
1405 | proto_tree_add_item(sub_tree, hf_tcpclv3_shutdown_flags_reason,
1406 | tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
1407 | proto_tree_add_item(sub_tree, hf_tcpclv3_shutdown_flags_delay,
1408 | tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
1409 |
1410 | offset += 1;
1411 | if (conv_hdr & TCPCLV3_SHUTDOWN_REASON) {
1412 | proto_tree_add_item(conv_tree,
1413 | hf_tcpclv3_shutdown_reason, tvb,
1414 | offset, 1, ENC_BIG_ENDIAN0x00000000);
1415 | offset += 1;
1416 | }
1417 | if (conv_hdr & TCPCLV3_SHUTDOWN_DELAY) {
1418 | proto_tree_add_item(conv_tree,
1419 | hf_tcpclv3_shutdown_delay, tvb,
1420 | offset, 2, ENC_BIG_ENDIAN0x00000000);
1421 | offset += 1;
1422 | }
1423 | break;
1424 | case TCPCLV3_REFUSE_BUNDLE:
1425 | /*No valid flags*/
1426 | offset += 1;
1427 |
1428 | refuse_bundle_hdr = tvb_get_uint8(tvb, offset);
1429 | proto_tree_add_item(conv_tree, hf_tcpclv3_refuse_reason_code, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
1430 | offset += 1;
1431 | col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const((refuse_bundle_hdr>>4)&0xF, v3_refuse_reason_code, "Unknown"));
1432 |
1433 | // implied transfer ID
1434 | xfer_id = wmem_map_lookup(ctx->rx_peer->frame_loc_to_transfer, ctx->cur_loc);
1435 | if (!xfer_id) {
1436 | xfer_id = wmem_new(pinfo->pool, uint64_t)((uint64_t*)wmem_alloc((pinfo->pool), sizeof(uint64_t)));
1437 | *xfer_id = wmem_map_size(ctx->rx_peer->transfers);
1438 |
1439 | tcpcl_peer_associate_transfer(ctx->rx_peer, ctx->cur_loc, *xfer_id);
1440 | }
1441 | item_xfer_id = proto_tree_add_uint64(conv_tree, hf_tcpclv3_xfer_id, tvb, 0, 0, *xfer_id);
1442 | proto_item_set_generated(item_xfer_id);
1443 |
1444 | if (tcpcl_analyze_sequence) {
1445 | transfer_add_refuse(ctx, *xfer_id, pinfo, tvb, conv_tree, conv_item);
1446 | }
1447 |
1448 | break;
1449 |
1450 | default:
1451 | expert_add_info(pinfo, proto_tree_get_parent(conv_tree), &ei_tcpclv3_invalid_msg_type);
1452 | break;
1453 | }
1454 |
1455 | return offset;
1456 | }
1457 |
1458 | static unsigned get_v4_msg_len(packet_info *pinfo _U___attribute__((unused)), tvbuff_t *tvb, int offset,
1459 | tcpcl_dissect_ctx_t *ctx _U___attribute__((unused))) {
1460 | const int init_offset = offset;
1461 | uint8_t msgtype = tvb_get_uint8(tvb, offset);
1462 | offset += 1;
1463 | switch(msgtype) {
1464 | case TCPCLV4_MSGTYPE_SESS_INIT: {
1465 | if (tvb_reported_length_remaining(tvb, offset) < 2 + 8 + 8 + 2) {
1466 | return 0;
1467 | }
1468 | offset += 2 + 8 + 8;
1469 | uint16_t nodeid_len = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1470 | offset += 2;
1471 | if (tvb_reported_length_remaining(tvb, offset) < nodeid_len + 4U) {
1472 | return 0;
1473 | }
1474 | offset += nodeid_len;
1475 | uint32_t extlist_len = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1476 | offset += 4;
1477 | if (ckd_add(&offset, offset, extlist_len)__builtin_add_overflow((offset), (extlist_len), (&offset) )) {
1478 | THROW(ReportedBoundsError)except_throw(1, (3), ((void*)0));
1479 | }
1480 | break;
1481 | }
1482 | case TCPCLV4_MSGTYPE_SESS_TERM: {
1483 | offset += 1 + 1;
1484 | break;
1485 | }
1486 | case TCPCLV4_MSGTYPE_XFER_SEGMENT: {
1487 | if (tvb_reported_length_remaining(tvb, offset) < 1) {
1488 | return 0;
1489 | }
1490 | uint8_t flags = tvb_get_uint8(tvb, offset);
1491 | offset += 1;
1492 | offset += 8;
1493 | if (flags & TCPCLV4_TRANSFER_FLAG_START) {
1494 | if (tvb_reported_length_remaining(tvb, offset) < 4) {
1495 | return 0;
1496 | }
1497 | uint32_t extlist_len = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1498 | offset += 4;
1499 | if ((unsigned)tvb_reported_length_remaining(tvb, offset) < extlist_len) {
1500 | return 0;
1501 | }
1502 | offset += extlist_len;
1503 | }
1504 | if (tvb_reported_length_remaining(tvb, offset) < 8) {
1505 | return 0;
1506 | }
1507 | uint64_t data_len = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1508 | offset += 8;
1509 | const int data_len_clamp = get_clamped_length(data_len, NULL((void*)0), NULL((void*)0));
1510 | if (ckd_add(&offset, offset, data_len_clamp)__builtin_add_overflow((offset), (data_len_clamp), (&offset ))) {
1511 | THROW(ReportedBoundsError)except_throw(1, (3), ((void*)0));
1512 | }
1513 | break;
1514 | }
1515 | case TCPCLV4_MSGTYPE_XFER_ACK: {
1516 | offset += 1 + 8 + 8;
1517 | break;
1518 | }
1519 | case TCPCLV4_MSGTYPE_XFER_REFUSE: {
1520 | offset += 1 + 8;
1521 | break;
1522 | }
1523 | case TCPCLV4_MSGTYPE_KEEPALIVE: {
1524 | break;
1525 | }
1526 | case TCPCLV4_MSGTYPE_MSG_REJECT: {
1527 | offset += 1 + 1;
1528 | break;
1529 | }
1530 | default:
1531 | // no known message
1532 | return 0;
1533 | }
1534 | return offset - init_offset;
1535 | }
1536 |
1537 | static int
1538 | dissect_v4_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1539 | tcpcl_dissect_ctx_t *ctx _U___attribute__((unused))) {
1540 | int offset = 0;
1541 | // Length of non-protocol 'payload' data in this message
1542 | int payload_len = 0;
1543 |
1544 | uint8_t msgtype = 0;
1545 | const char *msgtype_name = NULL((void*)0);
1546 |
1547 | proto_item *item_msg = proto_tree_add_item(tree, hf_tcpclv4_mhdr_tree, tvb, offset, 0, ENC_NA0x00000000);
1548 | proto_tree *tree_msg = proto_item_add_subtree(item_msg, ett_tcpclv4_mhdr);
1549 |
1550 | msgtype = tvb_get_uint8(tvb, offset);
1551 | proto_tree_add_uint(tree_msg, hf_tcpclv4_mhdr_type, tvb, offset, 1, msgtype);
1552 | offset += 1;
1553 | msgtype_name = val_to_str(pinfo->pool, msgtype, v4_message_type_vals, "type 0x%02" PRIx32"x");
1554 | wmem_strbuf_t *suffix_text = wmem_strbuf_new(pinfo->pool, NULL((void*)0));
1555 |
1556 | switch(msgtype) {
1557 | case TCPCLV4_MSGTYPE_SESS_INIT: {
1558 | uint16_t keepalive = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1559 | proto_tree_add_uint(tree_msg, hf_tcpclv4_sess_init_keepalive, tvb, offset, 2, keepalive);
1560 | offset += 2;
1561 |
1562 | uint64_t seg_mru = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1563 | proto_tree_add_uint64(tree_msg, hf_tcpclv4_sess_init_seg_mru, tvb, offset, 8, seg_mru);
1564 | offset += 8;
1565 |
1566 | uint64_t xfer_mru = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1567 | proto_tree_add_uint64(tree_msg, hf_tcpclv4_sess_init_xfer_mru, tvb, offset, 8, xfer_mru);
1568 | offset += 8;
1569 |
1570 | uint16_t nodeid_len = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1571 | proto_tree_add_uint(tree_msg, hf_tcpclv4_sess_init_nodeid_len, tvb, offset, 2, nodeid_len);
1572 | offset += 2;
1573 |
1574 | {
1575 | uint8_t *nodeid_data = tvb_get_string_enc(pinfo->pool, tvb, offset, nodeid_len, ENC_UTF_80x00000002);
1576 | proto_tree_add_string(tree_msg, hf_tcpclv4_sess_init_nodeid_data, tvb, offset, nodeid_len, (const char *)nodeid_data);
1577 | }
1578 | offset += nodeid_len;
1579 |
1580 | uint32_t extlist_len = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1581 | proto_tree_add_uint(tree_msg, hf_tcpclv4_sess_init_extlist_len, tvb, offset, 4, extlist_len);
1582 | offset += 4;
1583 |
1584 | int extlist_offset = 0;
1585 | while (extlist_offset < (int)extlist_len) {
1586 | int extitem_offset = 0;
1587 | proto_item *item_ext = proto_tree_add_item(tree_msg, hf_tcpclv4_sessext_tree, tvb, offset + extlist_offset, 0, ENC_NA0x00000000);
1588 | proto_tree *tree_ext = proto_item_add_subtree(item_ext, ett_tcpclv4_sessext);
1589 |
1590 | uint8_t extitem_flags = tvb_get_uint8(tvb, offset + extlist_offset + extitem_offset);
1591 | 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);
1592 | extitem_offset += 1;
1593 | const bool_Bool is_critical = (extitem_flags & TCPCLV4_EXTENSION_FLAG_CRITICAL);
1594 | if (is_critical) {
1595 | expert_add_info(pinfo, item_ext, &ei_tcpclv4_extitem_critical);
1596 | }
1597 |
1598 | uint16_t extitem_type = tvb_get_uint16(tvb, offset + extlist_offset + extitem_offset, ENC_BIG_ENDIAN0x00000000);
1599 | proto_item *item_type = proto_tree_add_uint(tree_ext, hf_tcpclv4_sessext_type, tvb, offset + extlist_offset + extitem_offset, 2, extitem_type);
1600 | extitem_offset += 2;
1601 |
1602 | dissector_handle_t subdis = dissector_get_uint_handle(xfer_ext_dissectors, extitem_type);
1603 | const char *subname = dissector_handle_get_description(subdis);
1604 | if (subdis) {
1605 | proto_item_set_text(item_type, "Item Type: %s (0x%04" PRIx16"hx" ")", subname, extitem_type);
1606 | }
1607 |
1608 | uint16_t extitem_len = tvb_get_uint16(tvb, offset + extlist_offset + extitem_offset, ENC_BIG_ENDIAN0x00000000);
1609 | proto_tree_add_uint(tree_ext, hf_tcpclv4_sessext_len, tvb, offset + extlist_offset + extitem_offset, 2, extitem_len);
1610 | extitem_offset += 2;
1611 |
1612 | tvbuff_t *extitem_tvb = tvb_new_subset_length(tvb, offset + extlist_offset + extitem_offset, extitem_len);
1613 | proto_item *item_extdata = proto_tree_add_item(tree_ext, hf_tcpclv4_sessext_data, extitem_tvb, 0, tvb_captured_length(extitem_tvb), ENC_NA0x00000000);
1614 | proto_tree *tree_extdata = proto_item_add_subtree(item_extdata, ett_tcpclv4_sessext_data);
1615 |
1616 | int sublen = 0;
1617 | if (subdis) {
1618 | sublen = call_dissector_only(subdis, extitem_tvb, pinfo, tree_extdata, NULL((void*)0));
1619 | }
1620 | if (sublen == 0) {
1621 | expert_add_info(pinfo, item_type, &ei_tcpclv4_invalid_sessext_type);
1622 | }
1623 | extitem_offset += extitem_len;
1624 |
1625 | proto_item_set_len(item_ext, extitem_offset);
1626 | extlist_offset += extitem_offset;
1627 |
1628 | if (subname) {
1629 | proto_item_append_text(item_ext, ": %s", subname);
1630 | }
1631 | else {
1632 | proto_item_append_text(item_ext, ": Type 0x%04" PRIx16"hx", extitem_type);
1633 | }
1634 | if (is_critical) {
1635 | proto_item_append_text(item_ext, ", CRITICAL");
1636 | }
1637 | }
1638 | // advance regardless of any internal offset processing
1639 | offset += extlist_len;
1640 |
1641 | if (ctx->tx_peer->sess_init_seen) {
1642 | if (tcpcl_analyze_sequence) {
1643 | if (!tcpcl_frame_loc_equal(ctx->tx_peer->sess_init_seen, ctx->cur_loc)) {
1644 | expert_add_info(pinfo, item_msg, &ei_tcpclv4_sess_init_duplicate);
1645 | }
1646 | }
1647 | }
1648 | else {
1649 | ctx->tx_peer->sess_init_seen = tcpcl_frame_loc_clone(wmem_file_scope(), ctx->cur_loc);
1650 | ctx->tx_peer->keepalive = keepalive;
1651 | ctx->tx_peer->segment_mru = seg_mru;
1652 | ctx->tx_peer->transfer_mru = xfer_mru;
1653 | }
1654 |
1655 | break;
1656 | }
1657 | case TCPCLV4_MSGTYPE_SESS_TERM: {
1658 | uint8_t flags = tvb_get_uint8(tvb, offset);
1659 | 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);
1660 | offset += 1;
1661 |
1662 | uint8_t reason = tvb_get_uint8(tvb, offset);
1663 | proto_tree_add_uint(tree_msg, hf_tcpclv4_sess_term_reason, tvb, offset, 1, reason);
1664 | offset += 1;
1665 |
1666 | if (ctx->tx_peer->sess_term_seen) {
1667 | if (tcpcl_analyze_sequence) {
1668 | if (!tcpcl_frame_loc_equal(ctx->tx_peer->sess_term_seen, ctx->cur_loc)) {
1669 | expert_add_info(pinfo, item_msg, &ei_tcpclv4_sess_term_duplicate);
1670 | }
1671 | }
1672 | }
1673 | else {
1674 | ctx->tx_peer->sess_term_seen = tcpcl_frame_loc_clone(wmem_file_scope(), ctx->cur_loc);
1675 | ctx->tx_peer->sess_term_reason = reason;
1676 | }
1677 |
1678 | if (tcpcl_analyze_sequence) {
1679 | if (ctx->rx_peer->sess_term_seen) {
1680 | 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);
1681 | proto_item_set_generated(item_rel);
1682 |
1683 | // Is this message after the other SESS_TERM?
1684 | if (tcpcl_frame_loc_compare(ctx->tx_peer->sess_term_seen, ctx->rx_peer->sess_term_seen, NULL((void*)0)) > 0) {
1685 | if (!(flags & TCPCLV4_SESS_TERM_FLAG_REPLY)) {
1686 | expert_add_info(pinfo, item_msg, &ei_tcpclv4_sess_term_reply_flag);
1687 | }
1688 | }
1689 | }
1690 | }
1691 |
1692 | break;
1693 | }
1694 | case TCPCLV4_MSGTYPE_XFER_SEGMENT:{
1695 | uint8_t flags = tvb_get_uint8(tvb, offset);
1696 | 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);
1697 | offset += 1;
1698 |
1699 | uint64_t xfer_id = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1700 | proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_id, tvb, offset, 8, xfer_id);
1701 | offset += 8;
1702 |
1703 | if (flags & TCPCLV4_TRANSFER_FLAG_START) {
1704 | uint32_t extlist_len = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1705 | proto_tree_add_uint(tree_msg, hf_tcpclv4_xfer_segment_extlist_len, tvb, offset, 4, extlist_len);
1706 | offset += 4;
1707 |
1708 | int extlist_offset = 0;
1709 | while (extlist_offset < (int)extlist_len) {
1710 | int extitem_offset = 0;
1711 | proto_item *item_ext = proto_tree_add_item(tree_msg, hf_tcpclv4_xferext_tree, tvb, offset + extlist_offset, 0, ENC_NA0x00000000);
1712 | proto_tree *tree_ext = proto_item_add_subtree(item_ext, ett_tcpclv4_xferext);
1713 |
1714 | uint8_t extitem_flags = tvb_get_uint8(tvb, offset + extlist_offset + extitem_offset);
1715 | 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);
1716 | extitem_offset += 1;
1717 | const bool_Bool is_critical = (extitem_flags & TCPCLV4_EXTENSION_FLAG_CRITICAL);
1718 | if (is_critical) {
1719 | expert_add_info(pinfo, item_ext, &ei_tcpclv4_extitem_critical);
1720 | }
1721 |
1722 | uint16_t extitem_type = tvb_get_uint16(tvb, offset + extlist_offset + extitem_offset, ENC_BIG_ENDIAN0x00000000);
1723 | proto_item *item_type = proto_tree_add_uint(tree_ext, hf_tcpclv4_xferext_type, tvb, offset + extlist_offset + extitem_offset, 2, extitem_type);
1724 | extitem_offset += 2;
1725 |
1726 | dissector_handle_t subdis = dissector_get_uint_handle(xfer_ext_dissectors, extitem_type);
1727 | const char *subname = dissector_handle_get_description(subdis);
1728 | if (subdis) {
1729 | proto_item_set_text(item_type, "Item Type: %s (0x%04" PRIx16"hx" ")", subname, extitem_type);
1730 | }
1731 |
1732 | uint16_t extitem_len = tvb_get_uint16(tvb, offset + extlist_offset + extitem_offset, ENC_BIG_ENDIAN0x00000000);
1733 | proto_tree_add_uint(tree_ext, hf_tcpclv4_xferext_len, tvb, offset + extlist_offset + extitem_offset, 2, extitem_len);
1734 | extitem_offset += 2;
1735 |
1736 | tvbuff_t *extitem_tvb = tvb_new_subset_length(tvb, offset + extlist_offset + extitem_offset, extitem_len);
1737 | proto_item *item_extdata = proto_tree_add_item(tree_ext, hf_tcpclv4_xferext_data, extitem_tvb, 0, tvb_captured_length(extitem_tvb), ENC_NA0x00000000);
1738 | proto_tree *tree_extdata = proto_item_add_subtree(item_extdata, ett_tcpclv4_xferext_data);
1739 |
1740 | tcpcl_frame_loc_t *extitem_loc = tcpcl_frame_loc_new(pinfo->pool, pinfo, extitem_tvb, 0);
1741 | tcpcl_peer_associate_transfer(ctx->tx_peer, extitem_loc, xfer_id);
1742 |
1743 | int sublen = 0;
1744 | if (subdis) {
1745 | sublen = call_dissector_only(subdis, extitem_tvb, pinfo, tree_extdata, NULL((void*)0));
1746 | }
1747 | if (sublen == 0) {
1748 | expert_add_info(pinfo, item_type, &ei_tcpclv4_invalid_xferext_type);
1749 | }
1750 | extitem_offset += extitem_len;
1751 |
1752 | proto_item_set_len(item_ext, extitem_offset);
1753 | extlist_offset += extitem_offset;
1754 |
1755 | if (subname) {
1756 | proto_item_append_text(item_ext, ": %s", subname);
1757 | }
1758 | else {
1759 | proto_item_append_text(item_ext, ": Type 0x%04" PRIx16"hx", extitem_type);
1760 | }
1761 | if (is_critical) {
1762 | proto_item_append_text(item_ext, ", CRITICAL");
1763 | }
1764 | }
1765 | // advance regardless of any internal offset processing
1766 | offset += extlist_len;
1767 | }
1768 |
1769 | uint64_t data_len = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1770 | proto_item *item_len = proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_segment_data_len, tvb, offset, 8, data_len);
1771 | offset += 8;
1772 |
1773 | if (data_len > ctx->rx_peer->segment_mru) {
1774 | expert_add_info(pinfo, item_len, &ei_tcpclv4_xfer_seg_over_seg_mru);
1775 | }
1776 | const int data_len_clamp = get_clamped_length(data_len, pinfo, item_len);
1777 |
1778 | // Treat data as payload layer
1779 | const int data_offset = offset;
1780 | proto_tree_add_item(tree_msg, hf_tcpclv4_xfer_segment_data, tvb, offset, data_len_clamp, ENC_NA0x00000000);
1781 | offset += data_len_clamp;
1782 | payload_len = data_len_clamp;
1783 |
1784 | wmem_strbuf_append_printf(suffix_text, ", Xfer ID: %" PRIi64"l" "i", xfer_id);
1785 |
1786 | if (flags) {
1787 | wmem_strbuf_append(suffix_text, ", Flags: ");
1788 | bool_Bool sep = false0;
1789 | if (flags & TCPCLV4_TRANSFER_FLAG_START) {
1790 | wmem_strbuf_append(suffix_text, "START");
1791 | sep = true1;
1792 | }
1793 | if (flags & TCPCLV4_TRANSFER_FLAG_END) {
1794 | if (sep) {
1795 | wmem_strbuf_append(suffix_text, "|");
1796 | }
1797 | wmem_strbuf_append(suffix_text, "END");
1798 | }
1799 | }
1800 |
1801 | if (tcpcl_analyze_sequence) {
1802 | transfer_add_segment(ctx, xfer_id, flags, data_len, pinfo, tvb, tree_msg, item_msg, item_flags);
1803 | }
1804 |
1805 | if (tcpcl_desegment_transfer) {
1806 | // Reassemble the segments
1807 | fragment_head *xferload_frag_msg = fragment_add_seq_next(
1808 | &xfer_reassembly_table,
1809 | tvb, data_offset,
1810 | pinfo, 0, &xfer_id,
1811 | data_len_clamp,
1812 | !(flags & TCPCLV4_TRANSFER_FLAG_END)
1813 | );
1814 | ctx->xferload = process_reassembled_data(
1815 | tvb, data_offset, pinfo,
1816 | "Reassembled Transfer",
1817 | xferload_frag_msg,
1818 | &xfer_frag_items,
1819 | NULL((void*)0),
1820 | tree
1821 | );
1822 | }
1823 |
1824 | break;
1825 | }
1826 | case TCPCLV4_MSGTYPE_XFER_ACK:{
1827 | uint8_t flags = tvb_get_uint8(tvb, offset);
1828 | 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);
1829 | offset += 1;
1830 |
1831 | uint64_t xfer_id = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1832 | proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_id, tvb, offset, 8, xfer_id);
1833 | offset += 8;
1834 |
1835 | uint64_t ack_len = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1836 | proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_ack_ack_len, tvb, offset, 8, ack_len);
1837 | offset += 8;
1838 |
1839 | wmem_strbuf_append_printf(suffix_text, ", Xfer ID: %" PRIi64"l" "i", xfer_id);
1840 |
1841 | if (flags) {
1842 | wmem_strbuf_append(suffix_text, ", Flags: ");
1843 | bool_Bool sep = false0;
1844 | if (flags & TCPCLV4_TRANSFER_FLAG_START) {
1845 | wmem_strbuf_append(suffix_text, "START");
1846 | sep = true1;
1847 | }
1848 | if (flags & TCPCLV4_TRANSFER_FLAG_END) {
1849 | if (sep) {
1850 | wmem_strbuf_append(suffix_text, "|");
1851 | }
1852 | wmem_strbuf_append(suffix_text, "END");
1853 | }
1854 | }
1855 |
1856 | if (tcpcl_analyze_sequence) {
1857 | transfer_add_ack(ctx, xfer_id, flags, ack_len, pinfo, tvb, tree_msg, item_msg, item_flags);
1858 | }
1859 |
1860 | break;
1861 | }
1862 | case TCPCLV4_MSGTYPE_XFER_REFUSE: {
1863 | uint8_t reason = tvb_get_uint8(tvb, offset);
1864 | proto_tree_add_uint(tree_msg, hf_tcpclv4_xfer_refuse_reason, tvb, offset, 1, reason);
1865 | offset += 1;
1866 |
1867 | uint64_t xfer_id = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN0x00000000);
1868 | proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_id, tvb, offset, 8, xfer_id);
1869 | offset += 8;
1870 |
1871 | wmem_strbuf_append_printf(suffix_text, ", Xfer ID: %" PRIi64"l" "i", xfer_id);
1872 |
1873 | if (tcpcl_analyze_sequence) {
1874 | transfer_add_refuse(ctx, xfer_id, pinfo, tvb, tree_msg, item_msg);
1875 | }
1876 |
1877 | break;
1878 | }
1879 | case TCPCLV4_MSGTYPE_KEEPALIVE: {
1880 | break;
1881 | }
1882 | case TCPCLV4_MSGTYPE_MSG_REJECT: {
1883 | uint8_t reason = tvb_get_uint8(tvb, offset);
1884 | proto_tree_add_uint(tree_msg, hf_tcpclv4_msg_reject_reason, tvb, offset, 1, reason);
1885 | offset += 1;
1886 |
1887 | uint8_t rej_head = tvb_get_uint8(tvb, offset);
1888 | proto_tree_add_uint(tree_msg, hf_tcpclv4_msg_reject_head, tvb, offset, 1, rej_head);
1889 | offset += 1;
1890 |
1891 | break;
1892 | }
1893 | default:
1894 | expert_add_info(pinfo, item_msg, &ei_tcpclv4_invalid_msg_type);
1895 | break;
1896 | }
1897 |
1898 | proto_item_set_len(item_msg, offset - payload_len);
1899 | proto_item_append_text(item_msg, ": %s%s", msgtype_name, wmem_strbuf_get_str(suffix_text));
1900 | wmem_strbuf_finalize(suffix_text);
1901 |
1902 | if (tcpcl_analyze_sequence) {
1903 | if (!(ctx->tx_peer->chdr_missing)) {
1904 | // assume the capture is somewhere in the middle
1905 | if (!(ctx->tx_peer->sess_init_seen)) {
1906 | expert_add_info(pinfo, item_msg, &ei_tcpclv4_sess_init_missing);
1907 | }
1908 | else {
1909 | // This message is before SESS_INIT (but is not the SESS_INIT)
1910 | const int cmp_sess_init = tcpcl_frame_loc_compare(ctx->cur_loc, ctx->tx_peer->sess_init_seen, NULL((void*)0));
1911 | if (((msgtype == TCPCLV4_MSGTYPE_SESS_INIT) && (cmp_sess_init < 0))
1912 | || ((msgtype != TCPCLV4_MSGTYPE_SESS_INIT) && (cmp_sess_init <= 0))) {
1913 | expert_add_info(pinfo, item_msg, &ei_tcpclv4_sess_init_missing);
1914 | }
1915 | }
1916 | }
1917 | }
1918 |
1919 | if (msgtype_name) {
1920 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), msgtype_name);
1921 | }
1922 |
1923 | try_negotiate(ctx, pinfo);
1924 | // Show negotiation results
1925 | if (msgtype == TCPCLV4_MSGTYPE_SESS_INIT) {
1926 | if (ctx->convo->sess_negotiated) {
1927 | if (ctx->rx_peer->sess_init_seen){
1928 | 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);
1929 | proto_item_set_generated(item_nego);
1930 | }
1931 | {
1932 | proto_item *item_nego = proto_tree_add_uint(tree_msg, hf_tcpclv4_negotiate_keepalive, tvb, 0, 0, ctx->convo->sess_keepalive);
1933 | proto_item_set_generated(item_nego);
1934 | }
1935 | }
1936 | }
1937 |
1938 | return offset;
1939 | }
1940 |
1941 | /** Function to extract a message length, or zero if not valid.
1942 | * This will call set_chdr_missing() if valid.
1943 | */
1944 | typedef unsigned (*chdr_missing_check)(packet_info *, tvbuff_t *, int offset, tcpcl_dissect_ctx_t *);
1945 |
1946 | /** Inspect a single segment to determine if this looks like a TLS record set.
1947 | */
1948 | static unsigned chdr_missing_tls(packet_info *pinfo, tvbuff_t *tvb, int offset,
1949 | tcpcl_dissect_ctx_t *ctx) {
1950 | if (ctx->convo->session_tls_start) {
1951 | // already in a TLS context
1952 | return 0;
1953 | }
1954 |
1955 | // similar heuristics to is_sslv3_or_tls() from packet-tls.c
1956 | if (tvb_captured_length(tvb) < 5) {
1957 | return 0;
1958 | }
1959 | uint8_t rectype = tvb_get_uint8(tvb, offset);
1960 | uint16_t recvers = tvb_get_uint16(tvb, offset+1, ENC_BIG_ENDIAN0x00000000);
1961 | uint16_t reclen = tvb_get_uint16(tvb, offset+1+2, ENC_BIG_ENDIAN0x00000000);
1962 |
1963 | switch(rectype) {
1964 | // These overlap with TCPCLV3_DATA_SEGMENT but have invalid flags
1965 | // They are valid but unallocated v4 message type codes
1966 | case SSL_ID_ALERT:
1967 | case SSL_ID_HANDSHAKE:
1968 | case SSL_ID_APP_DATA:
1969 | case SSL_ID_HEARTBEAT:
1970 | break;
1971 | default:
1972 | return 0;
1973 | }
1974 | if ((recvers & 0xFF00) != 0x0300) {
1975 | return 0;
1976 | }
1977 | if (reclen == 0 || reclen >= TLS_MAX_RECORD_LENGTH0x4000 + 2048) {
1978 | return 0;
1979 | }
1980 |
1981 | // post-STARTTLS
1982 | ctx->convo->session_use_tls = true1;
1983 | ctx->convo->session_tls_start = tcpcl_frame_loc_clone(wmem_file_scope(), ctx->cur_loc);
1984 | ssl_starttls_post_ack(tls_handle, pinfo, tcpcl_handle);
1985 |
1986 | return tvb_reported_length(tvb);
1987 |
1988 | }
1989 |
1990 | static unsigned chdr_missing_v3(packet_info *pinfo, tvbuff_t *tvb, int offset,
1991 | tcpcl_dissect_ctx_t *ctx) {
1992 | unsigned sublen = get_v3_msg_len(pinfo, tvb, offset, ctx);
1993 | if (sublen > 0) {
1994 | set_chdr_missing(ctx->tx_peer, 3);
1995 | }
1996 | return sublen;
1997 | }
1998 |
1999 | static unsigned chdr_missing_v4(packet_info *pinfo, tvbuff_t *tvb, int offset,
2000 | tcpcl_dissect_ctx_t *ctx) {
2001 | unsigned sublen = get_v4_msg_len(pinfo, tvb, offset, ctx);
2002 | if (sublen > 0) {
2003 | set_chdr_missing(ctx->tx_peer, 4);
2004 | }
2005 | return sublen;
2006 | }
2007 |
2008 | static const chdr_missing_check chdr_missing_v3first[] = {
2009 | &chdr_missing_tls,
2010 | &chdr_missing_v3,
2011 | &chdr_missing_v4,
2012 | NULL((void*)0)
2013 | };
2014 | static const chdr_missing_check chdr_missing_v3only[] = {
2015 | &chdr_missing_v3,
2016 | NULL((void*)0)
2017 | };
2018 | static const chdr_missing_check chdr_missing_v4first[] = {
2019 | &chdr_missing_tls,
2020 | &chdr_missing_v4,
2021 | &chdr_missing_v3,
2022 | NULL((void*)0)
2023 | };
2024 | static const chdr_missing_check chdr_missing_v4only[] = {
2025 | &chdr_missing_v4,
2026 | NULL((void*)0)
2027 | };
2028 |
2029 | static unsigned get_message_len(packet_info *pinfo, tvbuff_t *tvb, int ext_offset, void *data _U___attribute__((unused))) {
2030 | tcpcl_dissect_ctx_t *ctx = tcpcl_dissect_ctx_get(tvb, pinfo, ext_offset);
2031 | if (!ctx) {
2032 | return 0;
2033 | }
2034 | const unsigned init_offset = ext_offset;
2035 | unsigned offset = ext_offset;
2036 |
2037 | if (ctx->is_contact) {
2038 | if (tvb_memeql(tvb, offset, magic, sizeof(magic)) != 0) {
2039 | // Optional heuristic dissection of a message
2040 | const chdr_missing_check *checks = NULL((void*)0);
2041 | switch (tcpcl_chdr_missing) {
2042 | case CHDRMSN_V3FIRST:
2043 | checks = chdr_missing_v3first;
2044 | break;
2045 | case CHDRMSN_V3ONLY:
2046 | checks = chdr_missing_v3only;
2047 | break;
2048 | case CHDRMSN_V4FIRST:
2049 | checks = chdr_missing_v4first;
2050 | break;
2051 | case CHDRMSN_V4ONLY:
2052 | checks = chdr_missing_v4only;
2053 | break;
2054 | }
2055 | if (checks) {
2056 | for (const chdr_missing_check *chk = checks; *chk; ++chk) {
2057 | unsigned sublen = (**chk)(pinfo, tvb, offset, ctx);
2058 | if (sublen > 0) {
2059 | return sublen;
2060 | }
2061 | }
2062 | // no match
2063 | return 0;
2064 | }
2065 | else {
2066 | // require the contact header
2067 | const unsigned available = tvb_captured_length(tvb) - offset;
2068 | if (available < sizeof(magic) + 1) {
2069 | return DESEGMENT_ONE_MORE_SEGMENT0x0fffffff;
2070 | }
2071 | // sufficient size available but no match
2072 | return 0;
2073 | }
2074 | }
2075 | offset += sizeof(magic);
2076 |
2077 | uint8_t version = tvb_get_uint8(tvb, offset);
2078 | offset += 1;
2079 | if (version == 3) {
2080 | offset += 3; // flags + keepalive
2081 | uint64_t eid_len;
2082 | const unsigned bytecount = tvb_get_sdnv(tvb, offset, &eid_len);
2083 | const int len_clamp = get_clamped_length(eid_len, NULL((void*)0), NULL((void*)0));
2084 | offset += bytecount + len_clamp;
2085 | }
2086 | else if (version == 4) {
2087 | offset += 1; // flags
2088 | }
2089 | else {
2090 | return 0;
2091 | }
2092 | }
2093 | else {
2094 | if (ctx->tx_peer->version == 3) {
2095 | unsigned sublen = get_v3_msg_len(pinfo, tvb, offset, ctx);
2096 | if (sublen == 0) {
2097 | return 0;
2098 | }
2099 | offset += sublen;
2100 | }
2101 | else if (ctx->tx_peer->version == 4) {
2102 | unsigned sublen = get_v4_msg_len(pinfo, tvb, offset, ctx);
2103 | if (sublen == 0) {
2104 | return 0;
2105 | }
2106 | offset += sublen;
2107 | }
2108 | else {
2109 | return 0;
2110 | }
2111 | }
2112 | const int needlen = offset - init_offset;
2113 | return needlen;
2114 | }
2115 |
2116 | static int dissect_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused))) {
2117 | int offset = 0;
2118 | tcpcl_dissect_ctx_t *ctx = tcpcl_dissect_ctx_get(tvb, pinfo, offset);
2119 | if (!ctx) {
2120 | return 0;
2121 | }
2122 |
2123 | {
2124 | const char *proto_name = col_get_text(pinfo->cinfo, COL_PROTOCOL);
2125 | if (g_strcmp0(proto_name, proto_name_tcpcl) != 0) {
2126 | col_set_str(pinfo->cinfo, COL_PROTOCOL, proto_name_tcpcl);
2127 | col_clear(pinfo->cinfo, COL_INFO);
2128 | }
2129 | }
2130 |
2131 | // Append to the last TCPCL tree item if there is one
2132 | proto_item *item_tcpcl;
2133 | proto_tree *tree_tcpcl;
2134 | bool_Bool is_new_item_tcpcl = false0;
2135 | if (tree && (tree->last_child)
2136 | && (PITEM_HFINFO(tree->last_child)((tree->last_child)->hfinfo)->id == proto_tcpcl)) {
2137 | item_tcpcl = tree->last_child;
2138 | tree_tcpcl = proto_item_get_subtree(item_tcpcl);
2139 | }
2140 | else {
2141 | item_tcpcl = proto_tree_add_item(tree, proto_tcpcl, tvb, 0, -1, ENC_NA0x00000000);
2142 | tree_tcpcl = proto_item_add_subtree(item_tcpcl, ett_proto_tcpcl);
2143 | is_new_item_tcpcl = true1;
2144 | }
2145 |
2146 | if (ctx->tx_peer->chdr_missing) {
2147 | expert_add_info(pinfo, item_tcpcl, &ei_chdr_missing);
2148 | }
2149 | if (ctx->is_contact) {
2150 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), "Contact Header");
2151 |
2152 | proto_item *item_chdr = proto_tree_add_item(tree_tcpcl, hf_chdr_tree, tvb, offset, -1, ENC_NA0x00000000);
2153 | proto_tree *tree_chdr = proto_item_add_subtree(item_chdr, ett_chdr);
2154 |
2155 | proto_item *item_magic = proto_tree_add_item(tree_chdr, hf_chdr_magic, tvb, offset, sizeof(magic), ENC_NA0x00000000);
2156 | if (tvb_memeql(tvb, offset, magic, sizeof(magic)) != 0) {
2157 | expert_add_info(pinfo, item_magic, &ei_invalid_magic);
2158 | return 0;
2159 | }
2160 | offset += sizeof(magic);
2161 |
2162 | ctx->tx_peer->version = tvb_get_uint8(tvb, offset);
2163 | proto_item *item_version = proto_tree_add_uint(tree_chdr, hf_chdr_version, tvb, offset, 1, ctx->tx_peer->version);
2164 | offset += 1;
2165 |
2166 | // Mark or check version match
2167 | if (!ctx->convo->version) {
2168 | ctx->convo->version = wmem_new(wmem_file_scope(), uint8_t)((uint8_t*)wmem_alloc((wmem_file_scope()), sizeof(uint8_t)));
2169 | *(ctx->convo->version) = ctx->tx_peer->version;
2170 | }
2171 | else if (*(ctx->convo->version) != ctx->tx_peer->version) {
2172 | expert_add_info(pinfo, item_version, &ei_mismatch_version);
2173 | }
2174 |
2175 | if ((ctx->tx_peer->version < 3) || (ctx->tx_peer->version > 4)) {
2176 | expert_add_info(pinfo, item_version, &ei_invalid_version);
2177 | return offset;
2178 | }
2179 |
2180 | if (ctx->tx_peer->version == 3) {
2181 | /* Subtree to expand the bits in the Contact Header Flags */
2182 | proto_tree_add_bitmask(tree_chdr, tvb, offset, hf_tcpclv3_chdr_flags, ett_tcpclv3_chdr_flags, v3_chdr_flags, ENC_BIG_ENDIAN0x00000000);
2183 | offset++;
2184 |
2185 | proto_tree_add_item(tree_chdr, hf_tcpclv3_chdr_keep_alive, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000);
2186 | offset += 2;
2187 |
2188 | /*
2189 | * New format Contact header has length field followed by EID.
2190 | */
2191 | uint64_t eid_length;
2192 | int sdnv_length;
2193 | 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);
2194 | if (sdnv_length == 0) {
2195 | expert_add_info(pinfo, sub_item, &ei_tcpclv3_eid_length);
2196 | return 0;
2197 | }
2198 | offset += sdnv_length;
2199 | const int eid_len_clamp = get_clamped_length(eid_length, pinfo, sub_item);
2200 |
2201 | proto_tree_add_item(tree_chdr, hf_tcpclv3_chdr_local_eid, tvb, offset, eid_len_clamp, ENC_ASCII0x00000000);
2202 | offset += eid_len_clamp;
2203 |
2204 | // assumed parameters
2205 | ctx->tx_peer->segment_mru = UINT64_MAX(18446744073709551615UL);
2206 | ctx->tx_peer->transfer_mru = UINT64_MAX(18446744073709551615UL);
2207 | }
2208 | else if (ctx->tx_peer->version == 4) {
2209 | uint8_t flags = tvb_get_uint8(tvb, offset);
2210 | proto_tree_add_bitmask(tree_chdr, tvb, offset, hf_tcpclv4_chdr_flags, ett_tcpclv4_chdr_flags, v4_chdr_flags, ENC_BIG_ENDIAN0x00000000);
2211 | offset += 1;
2212 |
2213 | ctx->tx_peer->can_tls = (flags & TCPCLV4_CONTACT_FLAG_CANTLS);
2214 | }
2215 |
2216 | proto_item_set_len(item_chdr, offset);
2217 |
2218 | if (ctx->tx_peer->chdr_seen) {
2219 | if (tcpcl_analyze_sequence) {
2220 | if (!tcpcl_frame_loc_equal(ctx->tx_peer->chdr_seen, ctx->cur_loc)) {
2221 | expert_add_info(pinfo, item_chdr, &ei_chdr_duplicate);
2222 | }
2223 | }
2224 | }
2225 | else {
2226 | ctx->tx_peer->chdr_seen = tcpcl_frame_loc_clone(wmem_file_scope(), ctx->cur_loc);
2227 | }
2228 |
2229 | try_negotiate(ctx, pinfo);
2230 | // Show negotiation results
2231 | if (ctx->convo->contact_negotiated) {
2232 | if (ctx->rx_peer->chdr_seen) {
2233 | proto_item *item_nego = proto_tree_add_uint(tree_chdr, hf_chdr_related, tvb, 0, 0, ctx->rx_peer->chdr_seen->frame_num);
2234 | proto_item_set_generated(item_nego);
2235 | }
2236 | if (ctx->tx_peer->version == 4) {
2237 | proto_item *item_nego = proto_tree_add_boolean(tree_chdr, hf_tcpclv4_negotiate_use_tls, tvb, 0, 0, ctx->convo->session_use_tls);
2238 | proto_item_set_generated(item_nego);
2239 | }
2240 | }
2241 | }
2242 | else {
2243 | if (ctx->tx_peer->version == 3) {
2244 | offset += dissect_v3_msg(tvb, pinfo, tree_tcpcl, ctx);
2245 | }
2246 | else if (ctx->tx_peer->version == 4) {
2247 | offset += dissect_v4_msg(tvb, pinfo, tree_tcpcl, ctx);
2248 | }
2249 | }
2250 |
2251 | if (is_new_item_tcpcl) {
2252 | proto_item_set_len(item_tcpcl, offset);
2253 | proto_item_append_text(item_tcpcl, " Version %d", ctx->tx_peer->version);
2254 | }
2255 | else {
2256 | proto_item_set_len(item_tcpcl, proto_item_get_len(item_tcpcl) + offset);
2257 | }
2258 |
2259 | if (ctx->xferload) {
2260 | col_append_str(pinfo->cinfo, COL_INFO, " [Bundle]");
2261 |
2262 | if (tcpcl_decode_bundle) {
2263 | if (bundle_handle) {
2264 | call_dissector(
2265 | bundle_handle,
2266 | ctx->xferload,
2267 | pinfo,
2268 | tree
2269 | );
2270 | }
2271 | }
2272 | }
2273 |
2274 | return offset;
2275 | }
2276 |
2277 | static int
2278 | dissect_tcpcl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused)))
2279 | {
2280 | /* Retrieve information from conversation, or add it if it isn't
2281 | * there yet */
2282 | conversation_t *convo = find_or_create_conversation(pinfo);
2283 | tcpcl_conversation_t *tcpcl_convo = (tcpcl_conversation_t *)conversation_get_proto_data(convo, proto_tcpcl);
2284 | if (!tcpcl_convo) {
2285 | tcpcl_convo = tcpcl_conversation_new();
2286 | conversation_add_proto_data(convo, proto_tcpcl, tcpcl_convo);
2287 | // Assume the first source (i.e. TCP initiator) is the active node
2288 | copy_address_wmem(wmem_file_scope(), &(tcpcl_convo->active->addr), &(pinfo->src));
2289 | tcpcl_convo->active->port = pinfo->srcport;
2290 | copy_address_wmem(wmem_file_scope(), &(tcpcl_convo->passive->addr), &(pinfo->dst));
2291 | tcpcl_convo->passive->port = pinfo->destport;
2292 | }
2293 |
2294 | tcp_dissect_pdus(tvb, pinfo, tree, true1, 1, get_message_len, dissect_message, NULL((void*)0));
2295 |
2296 | const unsigned buflen = tvb_captured_length(tvb);
2297 | return buflen;
2298 | }
2299 |
2300 | static bool_Bool
2301 | dissect_tcpcl_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2302 | {
2303 | if (tvb_reported_length(tvb) < minimum_chdr_size) {
2304 | return false0;
2305 | }
2306 | if (tvb_memeql(tvb, 0, magic, sizeof(magic)) != 0) {
2307 | return false0;
2308 | }
2309 |
2310 | // treat the rest of the connection as TCPCL
2311 | conversation_t *convo = find_or_create_conversation(pinfo);
2312 | conversation_set_dissector(convo, tcpcl_handle);
2313 |
2314 | dissect_tcpcl(tvb, pinfo, tree, data);
2315 | return true1;
2316 | }
2317 |
2318 | static int dissect_xferext_transferlen(tvbuff_t *tvb, packet_info *pinfo _U___attribute__((unused)), proto_tree *tree, void *data _U___attribute__((unused))) {
2319 | int offset = 0;
2320 | tcpcl_dissect_ctx_t *ctx = tcpcl_dissect_ctx_get(tvb, pinfo, offset);
2321 | if (!ctx) {
2322 | return 0;
2323 | }
2324 |
2325 | uint64_t total_len = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN0x00000000);
2326 | proto_item *item_len = proto_tree_add_uint64(tree, hf_tcpclv4_xferext_transferlen_total_len, tvb, offset, 8, total_len);
2327 | offset += 8;
2328 | if (total_len > ctx->rx_peer->transfer_mru) {
2329 | expert_add_info(pinfo, item_len, &ei_tcpclv4_xferload_over_xfer_mru);
2330 | }
2331 |
2332 | if (tcpcl_analyze_sequence) {
2333 | uint64_t *xfer_id = wmem_map_lookup(ctx->tx_peer->frame_loc_to_transfer, ctx->cur_loc);
2334 | if (xfer_id) {
2335 | tcpcl_transfer_t *xfer = get_or_create_transfer_t(ctx->tx_peer->transfers, *xfer_id);
2336 | xfer->total_length = wmem_new(wmem_file_scope(), uint64_t)((uint64_t*)wmem_alloc((wmem_file_scope()), sizeof(uint64_t)) );
2337 | *(xfer->total_length) = total_len;
2338 | }
2339 | }
2340 |
2341 | return offset;
2342 | }
2343 |
2344 | static int dissect_othername_bundleeid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused))) {
2345 | int offset = 0;
2346 | asn1_ctx_t actx;
2347 | asn1_ctx_init(&actx, ASN1_ENC_BER, true1, pinfo);
2348 | offset += dissect_ber_restricted_string(
2349 | false0, BER_UNI_TAG_IA5String22,
2350 | &actx, tree, tvb, offset, hf_othername_bundleeid, NULL((void*)0)
2351 | );
2352 | return offset;
2353 | }
2354 |
2355 | /// Re-initialize after a configuration change
2356 | static void reinit_tcpcl(void) {
2357 | }
2358 |
2359 | void
2360 | proto_register_tcpcl(void)
2361 | {
2362 | expert_module_t *expert_tcpcl;
2363 |
2364 | proto_tcpcl = proto_register_protocol("DTN TCP Convergence Layer Protocol", "TCPCL", "tcpcl");
2365 |
2366 | proto_tcpcl_exts = proto_register_protocol_in_name_only(
2367 | "TCPCL Extension Subdissectors",
2368 | "TCPCL Extension Subdissectors",
2369 | "tcpcl_exts",
2370 | proto_tcpcl,
2371 | FT_PROTOCOL
2372 | );
2373 |
2374 | proto_register_field_array(proto_tcpcl, hf_tcpcl, array_length(hf_tcpcl)(sizeof (hf_tcpcl) / sizeof (hf_tcpcl)[0]));
2375 | proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0]));
2376 | expert_tcpcl = expert_register_protocol(proto_tcpcl);
2377 | expert_register_field_array(expert_tcpcl, ei_tcpcl, array_length(ei_tcpcl)(sizeof (ei_tcpcl) / sizeof (ei_tcpcl)[0]));
2378 |
2379 | tcpcl_handle = register_dissector("tcpcl", dissect_tcpcl, proto_tcpcl);
2380 | sess_ext_dissectors = register_dissector_table("tcpcl.v4.sess_ext", "TCPCLv4 Session Extension", proto_tcpcl, FT_UINT16, BASE_HEX);
2381 | xfer_ext_dissectors = register_dissector_table("tcpcl.v4.xfer_ext", "TCPCLv4 Transfer Extension", proto_tcpcl, FT_UINT16, BASE_HEX);
2382 |
2383 | module_t *module_tcpcl = prefs_register_protocol(proto_tcpcl, reinit_tcpcl);
2384 | prefs_register_enum_preference(
2385 | module_tcpcl,
2386 | "allow_chdr_missing",
2387 | "Allow missing Contact Header",
2388 | "Whether the TCPCL dissector should use heuristic "
2389 | "dissection of messages in the absence of a Contact Header "
2390 | "(if the capture misses the start of session).",
2391 | &tcpcl_chdr_missing,
2392 | chdr_missing_choices,
2393 | false0
2394 | );
2395 | prefs_register_bool_preference(
2396 | module_tcpcl,
2397 | "analyze_sequence",
2398 | "Analyze message sequences",
2399 | "Whether the TCPCL dissector should analyze the sequencing of "
2400 | "the messages within each session.",
2401 | &tcpcl_analyze_sequence
2402 | );
2403 | prefs_register_bool_preference(
2404 | module_tcpcl,
2405 | "desegment_transfer",
2406 | "Reassemble the segments of each transfer",
2407 | "Whether the TCPCL dissector should combine the sequential segments "
2408 | "of a transfer into the full bundle being transferred."
2409 | "To use this option, you must also enable "
2410 | "\"Allow subdissectors to reassemble TCP streams\" "
2411 | "in the TCP protocol settings.",
2412 | &tcpcl_desegment_transfer
2413 | );
2414 | prefs_register_bool_preference(
2415 | module_tcpcl,
2416 | "decode_bundle",
2417 | "Decode bundle data",
2418 | "If enabled, the transfer bundle will be decoded.",
2419 | &tcpcl_decode_bundle
2420 | );
2421 |
2422 | reassembly_table_register(
2423 | &xfer_reassembly_table,
2424 | &xfer_reassembly_table_functions
2425 | );
2426 |
2427 | }
2428 |
2429 | void
2430 | proto_reg_handoff_tcpcl(void)
2431 | {
2432 | tls_handle = find_dissector_add_dependency("tls", proto_tcpcl);
2433 | bundle_handle = find_dissector("bundle");
2434 |
2435 | dissector_add_uint_with_preference("tcp.port", BUNDLE_PORT4556, tcpcl_handle);
2436 | heur_dissector_add("tcp", dissect_tcpcl_heur, "TCPCL over TCP", "tcpcl_tcp", proto_tcpcl, HEURISTIC_ENABLE);
2437 |
2438 | /* Packaged extensions */
2439 | {
2440 | dissector_handle_t dis_h = create_dissector_handle_with_name_and_description(dissect_xferext_transferlen, proto_tcpcl_exts, NULL((void*)0), "Transfer Length");
2441 | dissector_add_uint("tcpcl.v4.xfer_ext", TCPCLV4_XFEREXT_TRANSFER_LEN, dis_h);
2442 | }
2443 |
2444 | register_ber_oid_dissector("1.3.6.1.5.5.7.3.35", NULL((void*)0), proto_tcpcl_exts, "id-kp-bundleSecurity");
2445 | register_ber_oid_dissector("1.3.6.1.5.5.7.8.11", dissect_othername_bundleeid, proto_tcpcl_exts, "id-on-bundleEID");
2446 |
2447 | reinit_tcpcl();
2448 | }
2449 |
2450 | /*
2451 | * Editor modelines - https://www.wireshark.org/tools/modelines.html
2452 | *
2453 | * Local variables:
2454 | * c-basic-offset: 4
2455 | * tab-width: 8
2456 | * indent-tabs-mode: nil
2457 | * End:
2458 | *
2459 | * vi: set shiftwidth=4 tabstop=8 expandtab:
2460 | * :indentSize=4:tabSize=8:noTabs=true:
2461 | */