Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-tcpcl.c
blob853161c1455e95ce405712ef04a88f6543726045
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
6 * TCPCLv4 portions copyright 2019-2021, Brian Sipos <brian.sipos@gmail.com>
7 * Copyright 2006-2007 The MITRE Corporation.
8 * All Rights Reserved.
9 * Approved for Public Release; Distribution Unlimited.
10 * Tracking Number 07-0090.
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.
17 * Wireshark - Network traffic analyzer
18 * By Gerald Combs <gerald@wireshark.org>
19 * Copyright 1998 Gerald Combs
21 * SPDX-License-Identifier: GPL-2.0-or-later
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.
29 * Released under the GNU GPL with NASA legal approval granted 2016-06-10.
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.
39 #include "config.h"
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 <wsutil/array.h>
48 #include "packet-tls-utils.h"
49 #include "packet-tcp.h"
50 #include "packet-ber.h"
51 #include "packet-bpv6.h"
52 #include "packet-tcpcl.h"
54 void proto_register_tcpcl(void);
55 void proto_reg_handoff_tcpcl(void);
57 /// Contact header magic bytes
58 static const char magic[] = {'d', 't', 'n', '!'};
59 /// Minimum size of contact header for any version
60 static const unsigned minimum_chdr_size = 6;
62 /// Options for missing contact header handling
63 enum AllowContactHeaderMissing {
64 CHDRMSN_DISABLE,
65 CHDRMSN_V3FIRST,
66 CHDRMSN_V3ONLY,
67 CHDRMSN_V4FIRST,
68 CHDRMSN_V4ONLY,
71 static const enum_val_t chdr_missing_choices[] = {
72 {"disabled", "Disabled", CHDRMSN_DISABLE},
73 {"v4first", "Try TCPCLv4 first", CHDRMSN_V4FIRST},
74 {"v4only", "Only TCPCLv4", CHDRMSN_V4ONLY},
75 {"v3first", "Try TCPCLv3 first", CHDRMSN_V3FIRST},
76 {"v3only", "Only TCPCLv3", CHDRMSN_V3ONLY},
77 {NULL, NULL, 0},
80 static int proto_tcpcl;
81 static int proto_tcpcl_exts;
82 /// Protocol column name
83 static const char *const proto_name_tcpcl = "TCPCL";
85 static int tcpcl_chdr_missing = CHDRMSN_V4FIRST;
86 static bool tcpcl_desegment_transfer = true;
87 static bool tcpcl_analyze_sequence = true;
88 static bool tcpcl_decode_bundle = true;
90 /* For Reassembling TCP Convergence Layer segments */
91 static reassembly_table xfer_reassembly_table;
93 /// Dissector handles
94 static dissector_handle_t tcpcl_handle;
95 static dissector_handle_t tls_handle;
96 static dissector_handle_t bundle_handle;
98 /// Extension sub-dissectors
99 static dissector_table_t sess_ext_dissectors;
100 static dissector_table_t xfer_ext_dissectors;
102 static const value_string v3_message_type_vals[] = {
103 {((TCPCLV3_DATA_SEGMENT>>4) & 0x0F), "DATA_SEGMENT"},
104 {((TCPCLV3_ACK_SEGMENT>>4) & 0x0F), "ACK_SEGMENT"},
105 {((TCPCLV3_REFUSE_BUNDLE>>4) & 0x0F), "REFUSE_BUNDLE"},
106 {((TCPCLV3_KEEP_ALIVE>>4) & 0x0F), "KEEPALIVE"},
107 {((TCPCLV3_SHUTDOWN>>4) & 0x0F), "SHUTDOWN"},
108 {((TCPCLV3_LENGTH>>4) & 0x0F), "LENGTH"},
109 {0, NULL}
112 /* Refuse-Bundle Reason-Code Flags as per RFC-7242: Section-5.4 */
113 static const value_string v3_refuse_reason_code[] = {
114 {TCPCLV3_REFUSE_REASON_UNKNOWN, "Reason for refusal is unknown"},
115 {TCPCLV3_REFUSE_REASON_RX_COMPLETE, "Complete Bundle Received"},
116 {TCPCLV3_REFUSE_REASON_RX_EXHAUSTED, "Receiver's resources exhausted"},
117 {TCPCLV3_REFUSE_REASON_RX_RETRANSMIT, "Receiver expects re-transmission of bundle"},
118 {0, NULL}
121 static const value_string v4_message_type_vals[]={
122 {TCPCLV4_MSGTYPE_SESS_INIT, "SESS_INIT"},
123 {TCPCLV4_MSGTYPE_SESS_TERM, "SESS_TERM"},
124 {TCPCLV4_MSGTYPE_MSG_REJECT, "MSG_REJECT"},
125 {TCPCLV4_MSGTYPE_KEEPALIVE, "KEEPALIVE"},
126 {TCPCLV4_MSGTYPE_XFER_SEGMENT, "XFER_SEGMENT"},
127 {TCPCLV4_MSGTYPE_XFER_ACK, "XFER_ACK"},
128 {TCPCLV4_MSGTYPE_XFER_REFUSE, "XFER_REFUSE"},
129 {0, NULL},
132 static const value_string v4_sess_term_reason_vals[]={
133 {0x00, "Unknown"},
134 {0x01, "Idle timeout"},
135 {0x02, "Version mismatch"},
136 {0x03, "Busy"},
137 {0x04, "Contact Failure"},
138 {0x05, "Resource Exhaustion"},
139 {0, NULL},
142 static const value_string v4_xfer_refuse_reason_vals[]={
143 {0x00, "Unknown"},
144 {0x01, "Completed"},
145 {0x02, "No Resources"},
146 {0x03, "Retransmit"},
147 {0x04, "Not Acceptable"},
148 {0x05, "Extension Failure"},
149 {0, NULL},
152 static const value_string v4_msg_reject_reason_vals[]={
153 {0x00, "reserved"},
154 {0x01, "Message Type Unknown"},
155 {0x02, "Message Unsupported"},
156 {0x03, "Message Unexpected"},
157 {0, NULL},
160 static int hf_chdr_tree;
161 static int hf_chdr_magic;
162 static int hf_chdr_version;
163 static int hf_chdr_related;
165 /* TCP Convergence Header Variables */
166 static int hf_tcpclv3_mhdr;
167 static int hf_tcpclv3_pkt_type;
169 /* Refuse-Bundle reason code */
170 static int hf_tcpclv3_refuse_reason_code;
172 static int hf_tcpclv3_chdr_flags;
173 static int hf_tcpclv3_chdr_keep_alive;
174 static int hf_tcpclv3_chdr_flags_ack_req;
175 static int hf_tcpclv3_chdr_flags_frag_enable;
176 static int hf_tcpclv3_chdr_flags_nak;
177 static int hf_tcpclv3_chdr_local_eid_length;
178 static int hf_tcpclv3_chdr_local_eid;
180 /* TCP Convergence Data Header Variables */
181 static int hf_tcpclv3_data_procflags;
182 static int hf_tcpclv3_data_procflags_start;
183 static int hf_tcpclv3_data_procflags_end;
184 static int hf_tcpclv3_xfer_id;
185 static int hf_tcpclv3_data_segment_length;
186 static int hf_tcpclv3_data_segment_data;
188 /* TCP Convergence Ack Variables */
189 static int hf_tcpclv3_ack_length;
191 /* TCP Convergence Shutdown Header Variables */
192 static int hf_tcpclv3_shutdown_flags;
193 static int hf_tcpclv3_shutdown_flags_reason;
194 static int hf_tcpclv3_shutdown_flags_delay;
195 static int hf_tcpclv3_shutdown_reason;
196 static int hf_tcpclv3_shutdown_delay;
198 static int hf_tcpclv4_chdr_flags;
199 static int hf_tcpclv4_chdr_flags_cantls;
200 static int hf_tcpclv4_negotiate_use_tls;
202 static int hf_tcpclv4_mhdr_tree;
203 static int hf_tcpclv4_mhdr_type;
204 static int hf_tcpclv4_sess_init_keepalive;
205 static int hf_tcpclv4_sess_init_seg_mru;
206 static int hf_tcpclv4_sess_init_xfer_mru;
207 static int hf_tcpclv4_sess_init_nodeid_len;
208 static int hf_tcpclv4_sess_init_nodeid_data;
209 static int hf_tcpclv4_sess_init_extlist_len;
210 static int hf_tcpclv4_sess_init_related;
211 static int hf_tcpclv4_negotiate_keepalive;
213 static int hf_tcpclv4_sess_term_flags;
214 static int hf_tcpclv4_sess_term_flags_reply;
215 static int hf_tcpclv4_sess_term_reason;
216 static int hf_tcpclv4_sess_term_related;
218 static int hf_tcpclv4_sessext_tree;
219 static int hf_tcpclv4_sessext_flags;
220 static int hf_tcpclv4_sessext_flags_crit;
221 static int hf_tcpclv4_sessext_type;
222 static int hf_tcpclv4_sessext_len;
223 static int hf_tcpclv4_sessext_data;
225 static int hf_tcpclv4_xferext_tree;
226 static int hf_tcpclv4_xferext_flags;
227 static int hf_tcpclv4_xferext_flags_crit;
228 static int hf_tcpclv4_xferext_type;
229 static int hf_tcpclv4_xferext_len;
230 static int hf_tcpclv4_xferext_data;
232 static int hf_tcpclv4_xfer_flags;
233 static int hf_tcpclv4_xfer_flags_start;
234 static int hf_tcpclv4_xfer_flags_end;
235 static int hf_tcpclv4_xfer_id;
236 static int hf_tcpclv4_xfer_total_len;
237 static int hf_tcpclv4_xfer_segment_extlist_len;
238 static int hf_tcpclv4_xfer_segment_data_len;
239 static int hf_tcpclv4_xfer_segment_data;
240 static int hf_tcpclv4_xfer_segment_seen_len;
241 static int hf_tcpclv4_xfer_segment_related_start;
242 static int hf_tcpclv4_xfer_segment_time_start;
243 static int hf_tcpclv4_xfer_segment_related_ack;
244 static int hf_tcpclv4_xfer_segment_time_diff;
245 static int hf_tcpclv4_xfer_ack_ack_len;
246 static int hf_tcpclv4_xfer_ack_related_start;
247 static int hf_tcpclv4_xfer_ack_time_start;
248 static int hf_tcpclv4_xfer_ack_related_seg;
249 static int hf_tcpclv4_xfer_ack_time_diff;
250 static int hf_tcpclv4_xfer_refuse_reason;
251 static int hf_tcpclv4_xfer_refuse_related_seg;
252 static int hf_tcpclv4_msg_reject_reason;
253 static int hf_tcpclv4_msg_reject_head;
255 static int hf_tcpclv4_xferext_transferlen_total_len;
257 static int hf_othername_bundleeid;
259 /*TCP Convergence Layer Reassembly boilerplate*/
260 static int hf_xfer_fragments;
261 static int hf_xfer_fragment;
262 static int hf_xfer_fragment_overlap;
263 static int hf_xfer_fragment_overlap_conflicts;
264 static int hf_xfer_fragment_multiple_tails;
265 static int hf_xfer_fragment_too_long_fragment;
266 static int hf_xfer_fragment_error;
267 static int hf_xfer_fragment_count;
268 static int hf_xfer_reassembled_in;
269 static int hf_xfer_reassembled_length;
270 static int hf_xfer_reassembled_data;
272 static hf_register_info hf_tcpcl[] = {
273 {&hf_chdr_tree, {"Contact Header", "tcpcl.contact_hdr", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
274 {&hf_chdr_magic, {"Protocol Magic", "tcpcl.contact_hdr.magic", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
275 {&hf_chdr_version, {"Version", "tcpcl.contact_hdr.version", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}},
276 {&hf_chdr_related, {"Related Header", "tcpcl.contact_hdr.related", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}},
278 {&hf_tcpclv3_mhdr,
279 {"TCPCLv3 Message", "tcpcl.mhdr",
280 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}
282 {&hf_tcpclv3_pkt_type,
283 {"Message Type", "tcpcl.pkt_type",
284 FT_UINT8, BASE_DEC, VALS(v3_message_type_vals), 0xF0, NULL, HFILL}
286 {&hf_tcpclv3_refuse_reason_code,
287 {"Reason-Code", "tcpcl.refuse.reason_code",
288 FT_UINT8, BASE_DEC, VALS(v3_refuse_reason_code), 0x0F, NULL, HFILL}
290 {&hf_tcpclv3_data_procflags,
291 {"Data Flags", "tcpcl.data.proc.flag",
292 FT_UINT8, BASE_HEX, NULL, TCPCLV3_DATA_FLAGS, NULL, HFILL}
294 {&hf_tcpclv3_data_procflags_start,
295 {"Segment contains start of bundle", "tcpcl.data.proc.start",
296 FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV3_DATA_START_FLAG, NULL, HFILL}
298 {&hf_tcpclv3_data_procflags_end,
299 {"Segment contains end of Bundle", "tcpcl.data.proc.end",
300 FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV3_DATA_END_FLAG, NULL, HFILL}
302 {&hf_tcpclv3_xfer_id, {"Implied Transfer ID", "tcpcl.xfer_id", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}},
303 {&hf_tcpclv3_data_segment_length,
304 {"Segment Length", "tcpcl.data.length",
305 FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL}
307 {&hf_tcpclv3_data_segment_data,
308 {"Segment Data", "tcpcl.data",
309 FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}
311 {&hf_tcpclv3_shutdown_flags,
312 {"TCP Convergence Shutdown Flags", "tcpcl.shutdown.flags",
313 FT_UINT8, BASE_HEX, NULL, TCPCLV3_SHUTDOWN_FLAGS, NULL, HFILL}
315 {&hf_tcpclv3_shutdown_flags_reason,
316 {"Shutdown includes Reason Code", "tcpcl.shutdown.reason.flag",
317 FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV3_SHUTDOWN_REASON, NULL, HFILL}
319 {&hf_tcpclv3_shutdown_flags_delay,
320 {"Shutdown includes Reconnection Delay", "tcpcl.shutdown.delay.flag",
321 FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV3_SHUTDOWN_DELAY, NULL, HFILL}
323 {&hf_tcpclv3_shutdown_reason,
324 {"Shutdown Reason Code", "tcpcl.shutdown.reason",
325 FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}
327 {&hf_tcpclv3_shutdown_delay,
328 {"Shutdown Reconnection Delay", "tcpcl.shutdown.delay",
329 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
331 {&hf_tcpclv3_ack_length,
332 {"Ack Length", "tcpcl.ack.length",
333 FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL}
335 {&hf_tcpclv3_chdr_flags,
336 {"Flags", "tcpcl.contact_hdr.flags",
337 FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
339 {&hf_tcpclv3_chdr_flags_ack_req,
340 {"Bundle Acks Requested", "tcpcl.contact_hdr.flags.ackreq",
341 FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV3_BUNDLE_ACK_FLAG, NULL, HFILL}
343 {&hf_tcpclv3_chdr_flags_frag_enable,
344 {"Reactive Fragmentation Enabled", "tcpcl.contact_hdr.flags.fragen",
345 FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV3_REACTIVE_FRAG_FLAG, NULL, HFILL}
347 {&hf_tcpclv3_chdr_flags_nak,
348 {"Support Negative Acknowledgements", "tcpcl.contact_hdr.flags.nak",
349 FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV3_CONNECTOR_RCVR_FLAG, NULL, HFILL}
351 {&hf_tcpclv3_chdr_keep_alive,
352 {"Keep Alive", "tcpcl.contact_hdr.keep_alive",
353 FT_UINT16, BASE_DEC|BASE_UNIT_STRING, UNS(&units_seconds), 0x0, NULL, HFILL}
355 {&hf_tcpclv3_chdr_local_eid,
356 {"Local EID", "tcpcl.contact_hdr.local_eid",
357 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}
359 {&hf_tcpclv3_chdr_local_eid_length,
360 {"Local EID Length", "tcpcl.contact_hdr.local_eid_length",
361 FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL}
364 {&hf_tcpclv4_chdr_flags, {"Contact Flags", "tcpcl.v4.chdr.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}},
365 {&hf_tcpclv4_chdr_flags_cantls, {"CAN_TLS", "tcpcl.v4.chdr.flags.can_tls", FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV4_CONTACT_FLAG_CANTLS, NULL, HFILL}},
366 // Contact negotiation results
367 {&hf_tcpclv4_negotiate_use_tls, {"Negotiated Use TLS", "tcpcl.v4.negotiated.use_tls", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}},
369 {&hf_tcpclv4_mhdr_tree, {"TCPCLv4 Message", "tcpcl.v4.mhdr", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
370 {&hf_tcpclv4_mhdr_type, {"Message Type", "tcpcl.v4.mhdr.type", FT_UINT8, BASE_HEX, VALS(v4_message_type_vals), 0x0, NULL, HFILL}},
372 // Session extension fields
373 {&hf_tcpclv4_sessext_tree, {"Session Extension Item", "tcpcl.v4.sessext", FT_PROTOCOL, BASE_NONE, NULL, 0x0, NULL, HFILL}},
374 {&hf_tcpclv4_sessext_flags, {"Item Flags", "tcpcl.v4.sessext.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}},
375 {&hf_tcpclv4_sessext_flags_crit, {"CRITICAL", "tcpcl.v4.sessext.flags.critical", FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV4_EXTENSION_FLAG_CRITICAL, NULL, HFILL}},
376 {&hf_tcpclv4_sessext_type, {"Item Type", "tcpcl.v4.sessext.type", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL}},
377 {&hf_tcpclv4_sessext_len, {"Item Length", "tcpcl.v4.sessext.len", FT_UINT32, BASE_DEC|BASE_UNIT_STRING, UNS(&units_octet_octets), 0x0, NULL, HFILL}},
378 {&hf_tcpclv4_sessext_data, {"Type-Specific Data", "tcpcl.v4.sessext.data", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
380 // Transfer extension fields
381 {&hf_tcpclv4_xferext_tree, {"Transfer Extension Item", "tcpcl.v4.xferext", FT_PROTOCOL, BASE_NONE, NULL, 0x0, NULL, HFILL}},
382 {&hf_tcpclv4_xferext_flags, {"Item Flags", "tcpcl.v4.xferext.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}},
383 {&hf_tcpclv4_xferext_flags_crit, {"CRITICAL", "tcpcl.v4.xferext.flags.critical", FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV4_EXTENSION_FLAG_CRITICAL, NULL, HFILL}},
384 {&hf_tcpclv4_xferext_type, {"Item Type", "tcpcl.v4.xferext.type", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL}},
385 {&hf_tcpclv4_xferext_len, {"Item Length", "tcpcl.v4.xferext.len", FT_UINT32, BASE_DEC|BASE_UNIT_STRING, UNS(&units_octet_octets), 0x0, NULL, HFILL}},
386 {&hf_tcpclv4_xferext_data, {"Type-Specific Data", "tcpcl.v4.xferext.data", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
388 // SESS_INIT fields
389 {&hf_tcpclv4_sess_init_keepalive, {"Keepalive Interval", "tcpcl.v4.sess_init.keepalive", FT_UINT16, BASE_DEC|BASE_UNIT_STRING, UNS(&units_seconds), 0x0, NULL, HFILL}},
390 {&hf_tcpclv4_sess_init_seg_mru, {"Segment MRU", "tcpcl.v4.sess_init.seg_mru", FT_UINT64, BASE_DEC|BASE_UNIT_STRING, UNS(&units_octet_octets), 0x0, NULL, HFILL}},
391 {&hf_tcpclv4_sess_init_xfer_mru, {"Transfer MRU", "tcpcl.v4.sess_init.xfer_mru", FT_UINT64, BASE_DEC|BASE_UNIT_STRING, UNS(&units_octet_octets), 0x0, NULL, HFILL}},
392 {&hf_tcpclv4_sess_init_nodeid_len, {"Node ID Length", "tcpcl.v4.sess_init.nodeid_len", FT_UINT16, BASE_DEC|BASE_UNIT_STRING, UNS(&units_octet_octets), 0x0, NULL, HFILL}},
393 {&hf_tcpclv4_sess_init_nodeid_data, {"Node ID Data (UTF8)", "tcpcl.v4.sess_init.nodeid_data", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
394 {&hf_tcpclv4_sess_init_extlist_len, {"Extension Items Length", "tcpcl.v4.sess_init.extlist_len", FT_UINT32, BASE_DEC|BASE_UNIT_STRING, UNS(&units_octet_octets), 0x0, NULL, HFILL}},
395 {&hf_tcpclv4_sess_init_related, {"Related SESS_INIT", "tcpcl.v4.sess_init.related", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}},
396 // Session negotiation results
397 {&hf_tcpclv4_negotiate_keepalive, {"Negotiated Keepalive Interval", "tcpcl.v4.negotiated.keepalive", FT_UINT16, BASE_DEC|BASE_UNIT_STRING, UNS(&units_seconds), 0x0, NULL, HFILL}},
398 // SESS_TERM fields
399 {&hf_tcpclv4_sess_term_flags, {"Flags", "tcpcl.v4.sess_term.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}},
400 {&hf_tcpclv4_sess_term_flags_reply, {"REPLY", "tcpcl.v4.sess_term.flags.reply", FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV4_SESS_TERM_FLAG_REPLY, NULL, HFILL}},
401 {&hf_tcpclv4_sess_term_reason, {"Reason", "tcpcl.v4.ses_term.reason", FT_UINT8, BASE_DEC, VALS(v4_sess_term_reason_vals), 0x0, NULL, HFILL}},
402 {&hf_tcpclv4_sess_term_related, {"Related SESS_TERM", "tcpcl.v4.ses_term.related", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}},
404 // Common transfer fields
405 {&hf_tcpclv4_xfer_flags, {"Transfer Flags", "tcpcl.v4.xfer_flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}},
406 {&hf_tcpclv4_xfer_flags_start, {"START", "tcpcl.v4.xfer_flags.start", FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV4_TRANSFER_FLAG_START, NULL, HFILL}},
407 {&hf_tcpclv4_xfer_flags_end, {"END", "tcpcl.v4.xfer_flags.end", FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV4_TRANSFER_FLAG_END, NULL, HFILL}},
408 {&hf_tcpclv4_xfer_id, {"Transfer ID", "tcpcl.v4.xfer_id", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}},
409 {&hf_tcpclv4_xfer_total_len, {"Expected Total Length", "tcpcl.v4.xfer.total_len", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL}},
410 // XFER_SEGMENT fields
411 {&hf_tcpclv4_xfer_segment_extlist_len, {"Extension Items Length", "tcpcl.v4.xfer_segment.extlist_len", FT_UINT32, BASE_DEC|BASE_UNIT_STRING, UNS(&units_octet_octets), 0x0, NULL, HFILL}},
412 {&hf_tcpclv4_xfer_segment_data_len, {"Segment Length", "tcpcl.v4.xfer_segment.data_len", FT_UINT64, BASE_DEC|BASE_UNIT_STRING, UNS(&units_octet_octets), 0x0, NULL, HFILL}},
413 {&hf_tcpclv4_xfer_segment_data, {"Segment Data", "tcpcl.v4.xfer_segment.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
414 {&hf_tcpclv4_xfer_segment_seen_len, {"Seen Length", "tcpcl.v4.xfer_segment.seen_len", FT_UINT64, BASE_DEC|BASE_UNIT_STRING, UNS(&units_octet_octets), 0x0, NULL, HFILL}},
415 {&hf_tcpclv4_xfer_segment_related_start, {"Related XFER_SEGMENT start", "tcpcl.v4.xfer_segment.related_start", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}},
416 {&hf_tcpclv4_xfer_segment_time_start, {"Time since transfer Start", "tcpcl.v4.xfer_segment.time_since_start", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL}},
417 {&hf_tcpclv4_xfer_segment_related_ack, {"Related XFER_ACK", "tcpcl.v4.xfer_segment.related_ack", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}},
418 {&hf_tcpclv4_xfer_segment_time_diff, {"Acknowledgment Time", "tcpcl.v4.xfer_segment.time_diff", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL}},
419 // XFER_ACK fields
420 {&hf_tcpclv4_xfer_ack_ack_len, {"Acknowledged Length", "tcpcl.v4.xfer_ack.ack_len", FT_UINT64, BASE_DEC|BASE_UNIT_STRING, UNS(&units_octet_octets), 0x0, NULL, HFILL}},
421 {&hf_tcpclv4_xfer_ack_related_start, {"Related XFER_SEGMENT start", "tcpcl.v4.xfer_ack.related_start", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}},
422 {&hf_tcpclv4_xfer_ack_time_start, {"Time since transfer Start", "tcpcl.v4.xfer_ack.time_since_start", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL}},
423 {&hf_tcpclv4_xfer_ack_related_seg, {"Related XFER_SEGMENT", "tcpcl.v4.xfer_ack.related_seg", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_ACK), 0x0, NULL, HFILL}},
424 {&hf_tcpclv4_xfer_ack_time_diff, {"Acknowledgment Time", "tcpcl.v4.xfer_ack.time_diff", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL}},
425 // XFER_REFUSE fields
426 {&hf_tcpclv4_xfer_refuse_reason, {"Reason", "tcpcl.v4.xfer_refuse.reason", FT_UINT8, BASE_DEC, VALS(v4_xfer_refuse_reason_vals), 0x0, NULL, HFILL}},
427 {&hf_tcpclv4_xfer_refuse_related_seg, {"Related XFER_SEGMENT", "tcpcl.v4.xfer_refuse.related_seg", FT_FRAMENUM, BASE_NONE, VALS(v4_xfer_refuse_reason_vals), 0x0, NULL, HFILL}},
428 // MSG_REJECT fields
429 {&hf_tcpclv4_msg_reject_reason, {"Reason", "tcpcl.v4.msg_reject.reason", FT_UINT8, BASE_DEC, VALS(v4_msg_reject_reason_vals), 0x0, NULL, HFILL}},
430 {&hf_tcpclv4_msg_reject_head, {"Rejected Type", "tcpcl.v4.msg_reject.head", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}},
432 // Specific extensions
433 {&hf_tcpclv4_xferext_transferlen_total_len, {"Total Length", "tcpcl.v4.xferext.transfer_length.total_len", FT_UINT64, BASE_DEC|BASE_UNIT_STRING, UNS(&units_octet_octets), 0x0, NULL, HFILL}},
434 // PKIX other name form
435 {&hf_othername_bundleeid, {"BundleEID", "tcpcl.v4.BundleEID", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
437 {&hf_xfer_fragments,
438 {"Transfer fragments", "tcpcl.xfer.fragments",
439 FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL } },
440 {&hf_xfer_fragment,
441 {"Transfer fragment", "tcpcl.xfer.fragment",
442 FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
443 {&hf_xfer_fragment_overlap,
444 {"Transfer fragment overlap", "tcpcl.xfer.fragment.overlap",
445 FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
446 {&hf_xfer_fragment_overlap_conflicts,
447 {"Transfer fragment overlapping with conflicting data",
448 "tcpcl.xfer.fragment.overlap.conflicts",
449 FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
450 {&hf_xfer_fragment_multiple_tails,
451 {"Message has multiple tail fragments",
452 "tcpcl.xfer.fragment.multiple_tails",
453 FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
454 {&hf_xfer_fragment_too_long_fragment,
455 {"Transfer fragment too long", "tcpcl.xfer.fragment.too_long_fragment",
456 FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
457 {&hf_xfer_fragment_error,
458 {"Transfer defragmentation error", "tcpcl.xfer.fragment.error",
459 FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
460 {&hf_xfer_fragment_count,
461 {"Transfer fragment count", "tcpcl.xfer.fragment.count",
462 FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
463 {&hf_xfer_reassembled_in,
464 {"Reassembled in", "tcpcl.xfer.reassembled.in",
465 FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
466 {&hf_xfer_reassembled_length,
467 {"Reassembled length", "tcpcl.xfer.reassembled.length",
468 FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
469 {&hf_xfer_reassembled_data,
470 {"Reassembled data", "tcpcl.xfer.reassembled.data",
471 FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL } },
475 static int *const v3_chdr_flags[] = {
476 &hf_tcpclv3_chdr_flags_ack_req,
477 &hf_tcpclv3_chdr_flags_frag_enable,
478 &hf_tcpclv3_chdr_flags_nak,
479 NULL
482 static int *const v3_data_procflags[] = {
483 &hf_tcpclv3_data_procflags_start,
484 &hf_tcpclv3_data_procflags_end,
485 NULL
487 static int *const v4_chdr_flags[] = {
488 &hf_tcpclv4_chdr_flags_cantls,
489 NULL
491 static int *const v4_sess_term_flags[] = {
492 &hf_tcpclv4_sess_term_flags_reply,
493 NULL
495 static int *const v4_xfer_flags[] = {
496 &hf_tcpclv4_xfer_flags_start,
497 &hf_tcpclv4_xfer_flags_end,
498 NULL
500 static int *const v4_sessext_flags[] = {
501 &hf_tcpclv4_sessext_flags_crit,
502 NULL
504 static int *const v4_xferext_flags[] = {
505 &hf_tcpclv4_xferext_flags_crit,
506 NULL
509 /* Tree Node Variables */
510 static int ett_proto_tcpcl;
511 static int ett_chdr;
512 static int ett_tcpclv3_chdr_flags;
513 static int ett_tcpclv3_mhdr;
514 static int ett_tcpclv3_data_procflags;
515 static int ett_tcpclv3_shutdown_flags;
516 static int ett_xfer_fragment;
517 static int ett_xfer_fragments;
518 static int ett_tcpclv4_chdr_flags;
519 static int ett_tcpclv4_mhdr;
520 static int ett_tcpclv4_sess_term_flags;
521 static int ett_tcpclv4_xfer_flags;
522 static int ett_tcpclv4_sessext;
523 static int ett_tcpclv4_sessext_flags;
524 static int ett_tcpclv4_sessext_data;
525 static int ett_tcpclv4_xferext;
526 static int ett_tcpclv4_xferext_flags;
527 static int ett_tcpclv4_xferext_data;
529 static int *ett[] = {
530 &ett_proto_tcpcl,
531 &ett_chdr,
532 &ett_tcpclv3_chdr_flags,
533 &ett_tcpclv3_mhdr,
534 &ett_tcpclv3_data_procflags,
535 &ett_tcpclv3_shutdown_flags,
536 &ett_tcpclv4_chdr_flags,
537 &ett_tcpclv4_mhdr,
538 &ett_tcpclv4_sess_term_flags,
539 &ett_tcpclv4_xfer_flags,
540 &ett_tcpclv4_sessext,
541 &ett_tcpclv4_sessext_flags,
542 &ett_tcpclv4_sessext_data,
543 &ett_tcpclv4_xferext,
544 &ett_tcpclv4_xferext_flags,
545 &ett_tcpclv4_xferext_data,
546 &ett_xfer_fragment,
547 &ett_xfer_fragments,
550 static expert_field ei_invalid_magic;
551 static expert_field ei_invalid_version;
552 static expert_field ei_mismatch_version;
553 static expert_field ei_chdr_duplicate;
554 static expert_field ei_length_clamped;
555 static expert_field ei_chdr_missing;
557 static expert_field ei_tcpclv3_eid_length;
558 static expert_field ei_tcpclv3_invalid_msg_type;
559 static expert_field ei_tcpclv3_data_flags;
560 static expert_field ei_tcpclv3_segment_length;
561 static expert_field ei_tcpclv3_ack_length;
563 static expert_field ei_tcpclv4_invalid_msg_type;
564 static expert_field ei_tcpclv4_invalid_sessext_type;
565 static expert_field ei_tcpclv4_invalid_xferext_type;
566 static expert_field ei_tcpclv4_extitem_critical;
567 static expert_field ei_tcpclv4_sess_init_missing;
568 static expert_field ei_tcpclv4_sess_init_duplicate;
569 static expert_field ei_tcpclv4_sess_term_duplicate;
570 static expert_field ei_tcpclv4_sess_term_reply_flag;
571 static expert_field ei_tcpclv4_xfer_seg_over_seg_mru;
572 static expert_field ei_tcpclv4_xfer_seg_missing_start;
573 static expert_field ei_tcpclv4_xfer_seg_duplicate_start;
574 static expert_field ei_tcpclv4_xfer_seg_missing_end;
575 static expert_field ei_tcpclv4_xfer_seg_duplicate_end;
576 static expert_field ei_tcpclv4_xfer_seg_no_relation;
577 static expert_field ei_xfer_seg_over_total_len;
578 static expert_field ei_xfer_mismatch_total_len;
579 static expert_field ei_xfer_ack_mismatch_flags;
580 static expert_field ei_xfer_ack_no_relation;
581 static expert_field ei_tcpclv4_xfer_refuse_no_transfer;
582 static expert_field ei_tcpclv4_xferload_over_xfer_mru;
584 static ei_register_info ei_tcpcl[] = {
585 {&ei_invalid_magic, { "tcpcl.invalid_contact_magic", PI_PROTOCOL, PI_ERROR, "Magic string is invalid", EXPFILL}},
586 {&ei_invalid_version, { "tcpcl.invalid_contact_version", PI_PROTOCOL, PI_ERROR, "Protocol version not handled", EXPFILL}},
587 {&ei_mismatch_version, { "tcpcl.mismatch_contact_version", PI_PROTOCOL, PI_ERROR, "Protocol version mismatch", EXPFILL}},
588 {&ei_chdr_duplicate, { "tcpcl.contact_duplicate", PI_SEQUENCE, PI_ERROR, "Duplicate Contact Header", EXPFILL}},
589 {&ei_length_clamped, { "tcpcl.length_clamped", PI_UNDECODED, PI_ERROR, "Length too large for Wireshark to handle", EXPFILL}},
590 {&ei_chdr_missing, { "tcpcl.contact_missing", PI_ASSUMPTION, PI_NOTE, "Contact Header is missing, TCPCL version is implied", EXPFILL}},
592 {&ei_tcpclv3_eid_length, { "tcpcl.eid_length_invalid", PI_PROTOCOL, PI_ERROR, "Invalid EID Length", EXPFILL }},
593 {&ei_tcpclv3_invalid_msg_type, { "tcpcl.unknown_message_type", PI_UNDECODED, PI_ERROR, "Message type is unknown", EXPFILL}},
594 {&ei_tcpclv3_data_flags, { "tcpcl.data.flags.invalid", PI_PROTOCOL, PI_WARN, "Invalid TCP CL Data Segment Flags", EXPFILL }},
595 {&ei_tcpclv3_segment_length, { "tcpcl.data.length.invalid", PI_PROTOCOL, PI_ERROR, "Invalid Data Length", EXPFILL }},
596 {&ei_tcpclv3_ack_length, { "tcpcl.ack.length.error", PI_PROTOCOL, PI_WARN, "Ack Length: Error", EXPFILL }},
598 {&ei_tcpclv4_invalid_msg_type, { "tcpcl.v4.unknown_message_type", PI_UNDECODED, PI_ERROR, "Message type is unknown", EXPFILL}},
599 {&ei_tcpclv4_invalid_sessext_type, { "tcpcl.v4.unknown_sessext_type", PI_UNDECODED, PI_WARN, "Session Extension type is unknown", EXPFILL}},
600 {&ei_tcpclv4_invalid_xferext_type, { "tcpcl.v4.unknown_xferext_type", PI_UNDECODED, PI_WARN, "Transfer Extension type is unknown", EXPFILL}},
601 {&ei_tcpclv4_extitem_critical, { "tcpcl.v4.extitem_critical", PI_REQUEST_CODE, PI_CHAT, "Extension Item is critical", EXPFILL}},
602 {&ei_tcpclv4_sess_init_missing, { "tcpcl.v4.sess_init_missing", PI_SEQUENCE, PI_ERROR, "Expected SESS_INIT message first", EXPFILL}},
603 {&ei_tcpclv4_sess_init_duplicate, { "tcpcl.v4.sess_init_duplicate", PI_SEQUENCE, PI_ERROR, "Duplicate SESS_INIT message", EXPFILL}},
604 {&ei_tcpclv4_sess_term_duplicate, { "tcpcl.v4.sess_term_duplicate", PI_SEQUENCE, PI_ERROR, "Duplicate SESS_TERM message", EXPFILL}},
605 {&ei_tcpclv4_sess_term_reply_flag, { "tcpcl.v4.sess_term_reply_flag", PI_SEQUENCE, PI_ERROR, "Reply SESS_TERM missing flag", EXPFILL}},
606 {&ei_tcpclv4_xfer_seg_over_seg_mru, { "tcpcl.v4.xfer_seg_over_seg_mru", PI_PROTOCOL, PI_WARN, "Segment data size larger than peer MRU", EXPFILL}},
607 {&ei_tcpclv4_xfer_seg_missing_start, { "tcpcl.v4.xfer_seg_missing_start", PI_SEQUENCE, PI_ERROR, "First XFER_SEGMENT is missing START flag", EXPFILL}},
608 {&ei_tcpclv4_xfer_seg_duplicate_start, { "tcpcl.v4.xfer_seg_duplicate_start", PI_SEQUENCE, PI_ERROR, "Non-first XFER_SEGMENT has START flag", EXPFILL}},
609 {&ei_tcpclv4_xfer_seg_missing_end, { "tcpcl.v4.xfer_seg_missing_end", PI_SEQUENCE, PI_ERROR, "Last XFER_SEGMENT is missing END flag", EXPFILL}},
610 {&ei_tcpclv4_xfer_seg_duplicate_end, { "tcpcl.v4.xfer_seg_duplicate_end", PI_SEQUENCE, PI_ERROR, "Non-last XFER_SEGMENT has END flag", EXPFILL}},
611 {&ei_tcpclv4_xfer_seg_no_relation, { "tcpcl.v4.xfer_seg_no_relation", PI_SEQUENCE, PI_NOTE, "XFER_SEGMENT has no related XFER_ACK", EXPFILL}},
612 {&ei_tcpclv4_xfer_refuse_no_transfer, { "tcpcl.v4.xfer_refuse_no_transfer", PI_SEQUENCE, PI_NOTE, "XFER_REFUSE has no related XFER_SEGMENT(s)", EXPFILL}},
613 {&ei_tcpclv4_xferload_over_xfer_mru, { "tcpcl.v4.xferload_over_xfer_mru", PI_SEQUENCE, PI_NOTE, "Transfer larger than peer MRU", EXPFILL}},
614 {&ei_xfer_seg_over_total_len, { "tcpcl.xfer_seg_over_total_len", PI_SEQUENCE, PI_ERROR, "XFER_SEGMENT has accumulated length beyond the Transfer Length extension", EXPFILL}},
615 {&ei_xfer_mismatch_total_len, { "tcpcl.xfer_mismatch_total_len", PI_SEQUENCE, PI_ERROR, "Transfer has total length different than the Transfer Length extension", EXPFILL}},
616 {&ei_xfer_ack_mismatch_flags, { "tcpcl.xfer_ack_mismatch_flags", PI_SEQUENCE, PI_ERROR, "XFER_ACK does not have flags matching XFER_SEGMENT", EXPFILL}},
617 {&ei_xfer_ack_no_relation, { "tcpcl.xfer_ack_no_relation", PI_SEQUENCE, PI_NOTE, "XFER_ACK has no related XFER_SEGMENT", EXPFILL}},
620 static const fragment_items xfer_frag_items = {
621 /*Fragment subtrees*/
622 &ett_xfer_fragment,
623 &ett_xfer_fragments,
624 /*Fragment Fields*/
625 &hf_xfer_fragments,
626 &hf_xfer_fragment,
627 &hf_xfer_fragment_overlap,
628 &hf_xfer_fragment_overlap_conflicts,
629 &hf_xfer_fragment_multiple_tails,
630 &hf_xfer_fragment_too_long_fragment,
631 &hf_xfer_fragment_error,
632 &hf_xfer_fragment_count,
633 /*Reassembled in field*/
634 &hf_xfer_reassembled_in,
635 /*Reassembled length field*/
636 &hf_xfer_reassembled_length,
637 /* Reassembled data field */
638 &hf_xfer_reassembled_data,
639 /*Tag*/
640 "Transfer fragments"
643 static unsigned tvb_get_sdnv(tvbuff_t *tvb, unsigned offset, uint64_t *value) {
644 return tvb_get_varint(tvb, offset, FT_VARINT_MAX_LEN, value, ENC_VARINT_SDNV);
647 static void tcpcl_frame_loc_init(tcpcl_frame_loc_t *loc, const packet_info *pinfo, tvbuff_t *tvb, const int offset) {
648 loc->frame_num = pinfo->num;
649 // This is a messy way to determine the index,
650 // but no other public functions allow determining how two TVB are related
651 loc->src_ix = -1;
652 for(GSList *srcit = pinfo->data_src; srcit != NULL; srcit = g_slist_next(srcit)) {
653 ++(loc->src_ix);
654 struct data_source *src = srcit->data;
655 if (get_data_source_tvb(src)->real_data == tvb->real_data) {
656 break;
659 loc->raw_offset = tvb_raw_offset(tvb) + offset;
662 /** Construct a new object on the file allocator.
664 static tcpcl_frame_loc_t * tcpcl_frame_loc_new(wmem_allocator_t *alloc, const packet_info *pinfo, tvbuff_t *tvb, const int offset) {
665 tcpcl_frame_loc_t *obj = wmem_new(alloc, tcpcl_frame_loc_t);
666 tcpcl_frame_loc_init(obj, pinfo, tvb, offset);
667 return obj;
670 /** Construct a new object on the file allocator.
672 static tcpcl_frame_loc_t * tcpcl_frame_loc_clone(wmem_allocator_t *alloc, const tcpcl_frame_loc_t *loc) {
673 tcpcl_frame_loc_t *obj = wmem_new(alloc, tcpcl_frame_loc_t);
674 *obj = *loc;
675 return obj;
678 #define tcpcl_frame_loc_free wmem_free
680 /** Function to match the GCompareDataFunc signature.
682 static int tcpcl_frame_loc_compare(const void *a, const void *b, void *user_data _U_) {
683 const tcpcl_frame_loc_t *aloc = a;
684 const tcpcl_frame_loc_t *bloc = b;
686 if (aloc->frame_num < bloc->frame_num) {
687 return -1;
689 else if (aloc->frame_num > bloc->frame_num) {
690 return 1;
693 if (aloc->raw_offset < bloc->raw_offset) {
694 return -1;
696 else if (aloc->raw_offset > bloc->raw_offset) {
697 return 1;
699 return 0;
702 /** Function to match the GCompareFunc signature.
704 static gboolean tcpcl_frame_loc_equal(const void *a, const void *b) {
705 const tcpcl_frame_loc_t *aobj = a;
706 const tcpcl_frame_loc_t *bobj = b;
707 return (
708 (aobj->frame_num == bobj->frame_num)
709 && (aobj->raw_offset == bobj->raw_offset)
713 /** Function to match the GHashFunc signature.
715 static unsigned tcpcl_frame_loc_hash(const void *key) {
716 const tcpcl_frame_loc_t *obj = key;
717 return (
718 g_int_hash(&(obj->frame_num))
719 ^ g_int_hash(&(obj->raw_offset))
723 struct tcpcl_ack_meta;
724 typedef struct tcpcl_ack_meta tcpcl_ack_meta_t;
725 struct tcpcl_seg_meta;
726 typedef struct tcpcl_seg_meta tcpcl_seg_meta_t;
728 struct tcpcl_seg_meta {
729 /// Location associated with this metadata
730 tcpcl_frame_loc_t frame_loc;
731 /// Timestamp on the frame (end time if reassembled)
732 nstime_t frame_time;
733 /// Copy of message flags
734 uint8_t flags;
735 /// Total transfer length including this segment
736 uint64_t seen_len;
738 /// Potential related start segment
739 tcpcl_seg_meta_t *related_start;
740 /// Potential related XFER_ACK
741 tcpcl_ack_meta_t *related_ack;
744 static tcpcl_seg_meta_t * tcpcl_seg_meta_new(const packet_info *pinfo, const tcpcl_frame_loc_t *loc) {
745 tcpcl_seg_meta_t *obj = wmem_new(wmem_file_scope(), tcpcl_seg_meta_t);
746 obj->frame_loc = *loc;
747 obj->frame_time = pinfo->abs_ts;
748 obj->flags = 0;
749 obj->seen_len = 0;
750 obj->related_start = NULL;
751 obj->related_ack = NULL;
752 return obj;
755 static void tcpcl_seg_meta_free(tcpcl_seg_meta_t *obj) {
756 wmem_free(wmem_file_scope(), obj);
759 /** Function to match the GCompareFunc signature.
761 static int tcpcl_seg_meta_compare_loc(const void *a, const void *b) {
762 return tcpcl_frame_loc_compare(
763 &(((tcpcl_seg_meta_t *)a)->frame_loc),
764 &(((tcpcl_seg_meta_t *)b)->frame_loc),
765 NULL
769 struct tcpcl_ack_meta {
770 /// Location associated with this metadata
771 tcpcl_frame_loc_t frame_loc;
772 /// Timestamp on the frame (end time if reassembled)
773 nstime_t frame_time;
774 /// Copy of message flags
775 uint8_t flags;
776 /// Total acknowledged length including this ack
777 uint64_t seen_len;
779 /// Potential related start segment
780 tcpcl_seg_meta_t *related_start;
781 /// Potential related XFER_SEGMENT
782 tcpcl_seg_meta_t *related_seg;
785 static tcpcl_ack_meta_t * tcpcl_ack_meta_new(const packet_info *pinfo, const tcpcl_frame_loc_t *loc) {
786 tcpcl_ack_meta_t *obj = wmem_new(wmem_file_scope(), tcpcl_ack_meta_t);
787 obj->frame_loc = *loc;
788 obj->frame_time = pinfo->abs_ts;
789 obj->flags = 0;
790 obj->seen_len = 0;
791 obj->related_start = NULL;
792 obj->related_seg = NULL;
793 return obj;
796 static void tcpcl_ack_meta_free(tcpcl_ack_meta_t *obj) {
797 wmem_free(wmem_file_scope(), obj);
800 /** Function to match the GCompareFunc signature.
802 static int tcpcl_ack_meta_compare_loc(const void *a, const void *b) {
803 return tcpcl_frame_loc_compare(
804 &(((tcpcl_seg_meta_t *)a)->frame_loc),
805 &(((tcpcl_seg_meta_t *)b)->frame_loc),
806 NULL
810 static tcpcl_transfer_t * tcpcl_transfer_new(void) {
811 tcpcl_transfer_t *obj = wmem_new(wmem_file_scope(), tcpcl_transfer_t);
812 obj->seg_list = wmem_list_new(wmem_file_scope());
813 obj->ack_list = wmem_list_new(wmem_file_scope());
814 obj->total_length = NULL;
815 return obj;
818 static tcpcl_transfer_t * get_or_create_transfer_t(wmem_map_t *table, const uint64_t xfer_id) {
819 tcpcl_transfer_t *xfer = wmem_map_lookup(table, &xfer_id);
820 if (!xfer) {
821 uint64_t *key = wmem_new(wmem_file_scope(), uint64_t);
822 *key = xfer_id;
823 xfer = tcpcl_transfer_new();
824 wmem_map_insert(table, key, xfer);
826 return xfer;
829 static tcpcl_peer_t * tcpcl_peer_new(void) {
830 tcpcl_peer_t *obj = wmem_new0(wmem_file_scope(), tcpcl_peer_t);
831 clear_address(&(obj->addr));
832 obj->frame_loc_to_transfer = wmem_map_new(wmem_file_scope(), tcpcl_frame_loc_hash, tcpcl_frame_loc_equal);
833 obj->transfers = wmem_map_new(wmem_file_scope(), g_int64_hash, g_int64_equal);
834 return obj;
837 static void tcpcl_peer_associate_transfer(tcpcl_peer_t *peer, const tcpcl_frame_loc_t *loc, const uint64_t xfer_id) {
838 void * *xfer = wmem_map_lookup(peer->frame_loc_to_transfer, loc);
839 if (!xfer) {
840 tcpcl_frame_loc_t *key = tcpcl_frame_loc_clone(wmem_file_scope(), loc);
841 uint64_t *val = wmem_new(wmem_file_scope(), uint64_t);
842 *val = xfer_id;
843 wmem_map_insert(peer->frame_loc_to_transfer, key, val);
847 static tcpcl_conversation_t * tcpcl_conversation_new(void) {
848 tcpcl_conversation_t *obj = wmem_new0(wmem_file_scope(), tcpcl_conversation_t);
849 obj->active = tcpcl_peer_new();
850 obj->passive = tcpcl_peer_new();
851 return obj;
854 tcpcl_dissect_ctx_t * tcpcl_dissect_ctx_get(tvbuff_t *tvb, packet_info *pinfo, const int offset) {
855 conversation_t *convo = find_or_create_conversation(pinfo);
856 tcpcl_conversation_t *tcpcl_convo = (tcpcl_conversation_t *)conversation_get_proto_data(convo, proto_tcpcl);
857 if (!tcpcl_convo) {
858 return NULL;
860 tcpcl_dissect_ctx_t *ctx = wmem_new0(wmem_packet_scope(), tcpcl_dissect_ctx_t);
861 ctx->convo = tcpcl_convo;
862 ctx->cur_loc = tcpcl_frame_loc_new(wmem_packet_scope(), pinfo, tvb, offset);
864 const bool src_is_active = (
865 addresses_equal(&(ctx->convo->active->addr), &(pinfo->src))
866 && (ctx->convo->active->port == pinfo->srcport)
868 if (src_is_active) {
869 ctx->tx_peer = ctx->convo->active;
870 ctx->rx_peer = ctx->convo->passive;
872 else {
873 ctx->tx_peer = ctx->convo->passive;
874 ctx->rx_peer = ctx->convo->active;
877 ctx->is_contact = (
878 !(ctx->tx_peer->chdr_missing)
879 && (
880 !(ctx->tx_peer->chdr_seen)
881 || tcpcl_frame_loc_equal(ctx->tx_peer->chdr_seen, ctx->cur_loc)
885 return ctx;
888 static void set_chdr_missing(tcpcl_peer_t *peer, uint8_t version) {
889 peer->chdr_missing = true;
890 peer->version = version;
891 // assumed parameters
892 peer->segment_mru = UINT64_MAX;
893 peer->transfer_mru = UINT64_MAX;
897 static void try_negotiate(tcpcl_dissect_ctx_t *ctx, packet_info *pinfo) {
898 if (!(ctx->convo->contact_negotiated)
899 && (ctx->convo->active->chdr_seen)
900 && (ctx->convo->passive->chdr_seen)) {
901 ctx->convo->session_use_tls = (
902 ctx->convo->active->can_tls & ctx->convo->passive->can_tls
904 ctx->convo->contact_negotiated = true;
906 if (ctx->convo->session_use_tls
907 && (!(ctx->convo->session_tls_start))) {
908 col_append_str(pinfo->cinfo, COL_INFO, " [STARTTLS]");
909 ctx->convo->session_tls_start = tcpcl_frame_loc_clone(wmem_file_scope(), ctx->cur_loc);
910 ssl_starttls_ack(tls_handle, pinfo, tcpcl_handle);
914 if (!(ctx->convo->sess_negotiated)
915 && (ctx->convo->active->sess_init_seen)
916 && (ctx->convo->passive->sess_init_seen)) {
917 ctx->convo->sess_keepalive = MIN(
918 ctx->convo->active->keepalive,
919 ctx->convo->passive->keepalive
921 ctx->convo->sess_negotiated = true;
926 typedef struct {
927 // key type for addresses_ports_reassembly_table_functions
928 void *addr_port;
929 // TCPCL ID
930 uint64_t xfer_id;
931 } tcpcl_fragment_key_t;
933 static unsigned fragment_key_hash(const void *ptr) {
934 const tcpcl_fragment_key_t *obj = (const tcpcl_fragment_key_t *)ptr;
935 return (
936 addresses_ports_reassembly_table_functions.hash_func(obj->addr_port)
937 ^ g_int64_hash(&(obj->xfer_id))
941 static gboolean fragment_key_equal(const void *ptrA, const void *ptrB) {
942 const tcpcl_fragment_key_t *objA = (const tcpcl_fragment_key_t *)ptrA;
943 const tcpcl_fragment_key_t *objB = (const tcpcl_fragment_key_t *)ptrB;
944 return (
945 addresses_ports_reassembly_table_functions.equal_func(objA->addr_port, objB->addr_port)
946 && (objA->xfer_id == objB->xfer_id)
950 static void *fragment_key_temporary(const packet_info *pinfo, const uint32_t id, const void *data) {
951 tcpcl_fragment_key_t *obj = g_slice_new(tcpcl_fragment_key_t);
952 obj->addr_port = addresses_ports_reassembly_table_functions.temporary_key_func(pinfo, id, NULL);
953 obj->xfer_id = *((const uint64_t *)data);
954 return (void *)obj;
957 static void *fragment_key_persistent(const packet_info *pinfo, const uint32_t id, const void *data) {
958 tcpcl_fragment_key_t *obj = g_slice_new(tcpcl_fragment_key_t);
959 obj->addr_port = addresses_ports_reassembly_table_functions.persistent_key_func(pinfo, id, NULL);
960 obj->xfer_id = *((const uint64_t *)data);
961 return (void *)obj;
964 static void fragment_key_free_temporary(void *ptr) {
965 tcpcl_fragment_key_t *obj = (tcpcl_fragment_key_t *)ptr;
966 if (obj) {
967 addresses_ports_reassembly_table_functions.free_temporary_key_func(obj->addr_port);
968 g_slice_free(tcpcl_fragment_key_t, obj);
972 static void fragment_key_free_persistent(void *ptr) {
973 tcpcl_fragment_key_t *obj = (tcpcl_fragment_key_t *)ptr;
974 if (obj) {
975 addresses_ports_reassembly_table_functions.free_persistent_key_func(obj->addr_port);
976 g_slice_free(tcpcl_fragment_key_t, obj);
980 static reassembly_table_functions xfer_reassembly_table_functions = {
981 fragment_key_hash,
982 fragment_key_equal,
983 fragment_key_temporary,
984 fragment_key_persistent,
985 fragment_key_free_temporary,
986 fragment_key_free_persistent
989 /** Record metadata about one segment in a transfer.
991 static void transfer_add_segment(tcpcl_dissect_ctx_t *ctx, uint64_t xfer_id, uint8_t flags,
992 uint64_t data_len,
993 packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree_msg,
994 proto_item *item_msg, proto_item *item_flags) {
995 tcpcl_transfer_t *xfer = get_or_create_transfer_t(ctx->tx_peer->transfers, xfer_id);
997 uint8_t flag_start, flag_end;
998 if (ctx->tx_peer->version == 3) {
999 flag_start = TCPCLV3_DATA_START_FLAG;
1000 flag_end = TCPCLV3_DATA_END_FLAG;
1002 else {
1003 flag_start = TCPCLV4_TRANSFER_FLAG_START;
1004 flag_end = TCPCLV4_TRANSFER_FLAG_END;
1007 // Add or get the segment metadata
1008 tcpcl_seg_meta_t *seg_meta = tcpcl_seg_meta_new(pinfo, ctx->cur_loc);
1009 wmem_list_frame_t *frm = wmem_list_find_custom(xfer->seg_list, seg_meta, tcpcl_seg_meta_compare_loc);
1010 if (frm) {
1011 tcpcl_seg_meta_free(seg_meta);
1012 seg_meta = wmem_list_frame_data(frm);
1014 else {
1015 wmem_list_insert_sorted(xfer->seg_list, seg_meta, tcpcl_seg_meta_compare_loc);
1016 frm = wmem_list_find_custom(xfer->seg_list, seg_meta, tcpcl_seg_meta_compare_loc);
1017 // Set for new item
1018 seg_meta->flags = flags;
1021 // mark start-of-transfer
1022 if (!(seg_meta->related_start)) {
1023 wmem_list_frame_t *frm_front = wmem_list_head(xfer->seg_list);
1024 tcpcl_seg_meta_t *seg_front = frm_front ? wmem_list_frame_data(frm_front) : NULL;
1025 if (seg_front && (seg_front->flags & flag_start)) {
1026 seg_meta->related_start = seg_front;
1030 // accumulate segment sizes
1031 uint64_t prev_seen_len;
1032 wmem_list_frame_t *frm_prev = wmem_list_frame_prev(frm);
1033 if (!frm_prev) {
1034 if (!(flags & flag_start)) {
1035 expert_add_info(pinfo, item_flags, &ei_tcpclv4_xfer_seg_missing_start);
1037 prev_seen_len = 0;
1039 else {
1040 const tcpcl_seg_meta_t *seg_prev = wmem_list_frame_data(frm_prev);
1041 if (flags & flag_start) {
1042 expert_add_info(pinfo, item_flags, &ei_tcpclv4_xfer_seg_duplicate_start);
1044 prev_seen_len = seg_prev->seen_len;
1046 wmem_list_frame_t *frm_next = wmem_list_frame_next(frm);
1047 if (!frm_next) {
1048 if (!(flags & flag_end)) {
1049 expert_add_info(pinfo, item_flags, &ei_tcpclv4_xfer_seg_missing_end);
1052 else {
1053 if (flags & flag_end) {
1054 expert_add_info(pinfo, item_flags, &ei_tcpclv4_xfer_seg_duplicate_end);
1057 seg_meta->seen_len = prev_seen_len + data_len;
1059 proto_item *item_seen = proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_segment_seen_len, tvb, 0, 0, seg_meta->seen_len);
1060 proto_item_set_generated(item_seen);
1061 if (seg_meta->seen_len > ctx->rx_peer->transfer_mru) {
1062 expert_add_info(pinfo, item_seen, &ei_tcpclv4_xferload_over_xfer_mru);
1064 if (xfer->total_length) {
1065 if (seg_meta->seen_len > *(xfer->total_length)) {
1066 expert_add_info(pinfo, item_seen, &ei_xfer_seg_over_total_len);
1068 else if ((flags & flag_end)
1069 && (seg_meta->seen_len != *(xfer->total_length))) {
1070 expert_add_info(pinfo, item_seen, &ei_xfer_mismatch_total_len);
1072 proto_item *item_total = proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_total_len, tvb, 0, 0, *(xfer->total_length));
1073 proto_item_set_generated(item_total);
1076 if (seg_meta->related_ack) {
1077 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);
1078 proto_item_set_generated(item_rel);
1080 nstime_t td;
1081 nstime_delta(&td, &(seg_meta->related_ack->frame_time), &(seg_meta->frame_time));
1082 proto_item *item_td = proto_tree_add_time(tree_msg, hf_tcpclv4_xfer_segment_time_diff, tvb, 0, 0, &td);
1083 proto_item_set_generated(item_td);
1086 else {
1087 expert_add_info(pinfo, item_msg, &ei_tcpclv4_xfer_seg_no_relation);
1089 if (seg_meta->related_start && (seg_meta->related_start != seg_meta)) {
1090 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);
1091 proto_item_set_generated(item_rel);
1093 nstime_t td;
1094 nstime_delta(&td, &(seg_meta->frame_time), &(seg_meta->related_start->frame_time));
1095 proto_item *item_td = proto_tree_add_time(tree_msg, hf_tcpclv4_xfer_segment_time_start, tvb, 0, 0, &td);
1096 proto_item_set_generated(item_td);
1100 static void transfer_add_ack(tcpcl_dissect_ctx_t *ctx, uint64_t xfer_id, uint8_t flags,
1101 uint64_t ack_len,
1102 packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree_msg,
1103 proto_item *item_msg, proto_item *item_flags) {
1104 tcpcl_transfer_t *xfer = get_or_create_transfer_t(ctx->rx_peer->transfers, xfer_id);
1106 // Add or get the ack metadata
1107 tcpcl_ack_meta_t *ack_meta = tcpcl_ack_meta_new(pinfo, ctx->cur_loc);
1108 wmem_list_frame_t *frm = wmem_list_find_custom(xfer->ack_list, ack_meta, tcpcl_ack_meta_compare_loc);
1109 if (frm) {
1110 tcpcl_ack_meta_free(ack_meta);
1111 ack_meta = wmem_list_frame_data(frm);
1113 else {
1114 wmem_list_insert_sorted(xfer->ack_list, ack_meta, tcpcl_ack_meta_compare_loc);
1115 wmem_list_find_custom(xfer->ack_list, ack_meta, tcpcl_ack_meta_compare_loc);
1116 // Set for new item
1117 ack_meta->flags = flags;
1118 ack_meta->seen_len = ack_len;
1121 // mark start-of-transfer
1122 if (!(ack_meta->related_start)) {
1123 wmem_list_frame_t *frm_front = wmem_list_head(xfer->seg_list);
1124 tcpcl_seg_meta_t *seg_front = frm_front ? wmem_list_frame_data(frm_front) : NULL;
1125 if (seg_front && (seg_front->flags & TCPCLV4_TRANSFER_FLAG_START)) {
1126 ack_meta->related_start = seg_front;
1130 // Assemble both of the links here, as ACK will always follow segment
1131 if (!(ack_meta->related_seg)) {
1132 wmem_list_frame_t *seg_iter = wmem_list_head(xfer->seg_list);
1133 for (; seg_iter; seg_iter = wmem_list_frame_next(seg_iter)) {
1134 tcpcl_seg_meta_t *seg_meta = wmem_list_frame_data(seg_iter);
1135 if (seg_meta->seen_len == ack_meta->seen_len) {
1136 seg_meta->related_ack = ack_meta;
1137 ack_meta->related_seg = seg_meta;
1142 if (xfer->total_length) {
1143 proto_item *item_total = proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_total_len, tvb, 0, 0, *(xfer->total_length));
1144 proto_item_set_generated(item_total);
1146 if (ack_meta->related_seg) {
1147 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);
1148 proto_item_set_generated(item_rel);
1150 nstime_t td;
1151 nstime_delta(&td, &(ack_meta->frame_time), &(ack_meta->related_seg->frame_time));
1152 proto_item *item_td = proto_tree_add_time(tree_msg, hf_tcpclv4_xfer_ack_time_diff, tvb, 0, 0, &td);
1153 proto_item_set_generated(item_td);
1155 if (item_flags && (ack_meta->flags != ack_meta->related_seg->flags)) {
1156 expert_add_info(pinfo, item_flags, &ei_xfer_ack_mismatch_flags);
1159 else {
1160 expert_add_info(pinfo, item_msg, &ei_xfer_ack_no_relation);
1162 if (ack_meta->related_start) {
1163 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);
1164 proto_item_set_generated(item_rel);
1166 nstime_t td;
1167 nstime_delta(&td, &(ack_meta->frame_time), &(ack_meta->related_start->frame_time));
1168 proto_item *item_td = proto_tree_add_time(tree_msg, hf_tcpclv4_xfer_ack_time_start, tvb, 0, 0, &td);
1169 proto_item_set_generated(item_td);
1173 static void transfer_add_refuse(tcpcl_dissect_ctx_t *ctx, uint64_t xfer_id,
1174 packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree_msg,
1175 proto_item *item_msg) {
1176 const tcpcl_transfer_t *xfer = wmem_map_lookup(ctx->rx_peer->transfers, &xfer_id);
1177 const tcpcl_seg_meta_t *seg_last = NULL;
1178 if (xfer) {
1179 wmem_list_frame_t *seg_iter = wmem_list_tail(xfer->seg_list);
1180 seg_iter = seg_iter ? wmem_list_frame_prev(seg_iter) : NULL;
1181 seg_last = seg_iter ? wmem_list_frame_data(seg_iter) : NULL;
1184 if (seg_last) {
1185 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);
1186 proto_item_set_generated(item_rel);
1188 else {
1189 expert_add_info(pinfo, item_msg, &ei_tcpclv4_xfer_refuse_no_transfer);
1193 static int get_clamped_length(uint64_t orig, packet_info *pinfo, proto_item *item) {
1194 int clamped;
1195 if (orig > INT_MAX) {
1196 clamped = INT_MAX;
1197 if (pinfo && item) {
1198 expert_add_info(pinfo, item, &ei_length_clamped);
1201 else {
1202 clamped = (int) orig;
1204 return clamped;
1207 static unsigned
1208 get_v3_msg_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset,
1209 tcpcl_dissect_ctx_t *ctx _U_)
1211 const int orig_offset = offset;
1212 uint64_t len;
1213 unsigned bytecount;
1214 uint8_t conv_hdr = tvb_get_uint8(tvb, offset);
1215 offset += 1;
1217 switch (conv_hdr & TCPCLV3_TYPE_MASK)
1219 case TCPCLV3_DATA_SEGMENT: {
1220 /* get length from sdnv */
1221 bytecount = tvb_get_sdnv(tvb, offset, &len);
1222 if (bytecount == 0) {
1223 return 0;
1225 const int len_clamp = get_clamped_length(len, NULL, NULL);
1226 offset += bytecount + len_clamp;
1227 break;
1229 case TCPCLV3_ACK_SEGMENT:
1230 /* get length from sdnv */
1231 bytecount = tvb_get_sdnv(tvb, offset, &len);
1232 if (bytecount == 0) {
1233 return 0;
1235 offset += bytecount;
1236 break;
1238 case TCPCLV3_KEEP_ALIVE:
1239 case TCPCLV3_REFUSE_BUNDLE:
1240 /* always 1 byte */
1241 break;
1242 case TCPCLV3_SHUTDOWN:
1243 if (conv_hdr & TCPCLV3_SHUTDOWN_REASON) {
1244 offset += 1;
1246 if (conv_hdr & TCPCLV3_SHUTDOWN_DELAY) {
1247 offset += 2;
1249 break;
1251 case TCPCLV3_LENGTH:
1252 /* get length from sdnv */
1253 bytecount = tvb_get_sdnv(tvb, offset, &len);
1254 if (bytecount == 0) {
1255 return 0;
1257 offset += bytecount;
1258 break;
1260 default:
1261 // no known message
1262 return 0;
1265 return offset - orig_offset;
1268 static int
1269 dissect_v3_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1270 tcpcl_dissect_ctx_t *ctx)
1272 uint8_t conv_hdr;
1273 const char *msgtype_name;
1274 uint8_t refuse_bundle_hdr;
1275 int offset = 0;
1276 int sdnv_length;
1277 uint64_t segment_length;
1278 proto_item *conv_item, *sub_item;
1279 proto_tree *conv_tree, *sub_tree;
1280 uint64_t *xfer_id = NULL;
1281 proto_item *item_xfer_id = NULL;
1283 conv_item = proto_tree_add_item(tree, hf_tcpclv3_mhdr, tvb, 0, -1, ENC_NA);
1284 conv_tree = proto_item_add_subtree(conv_item, ett_tcpclv3_mhdr);
1286 conv_hdr = tvb_get_uint8(tvb, offset);
1287 proto_tree_add_item(conv_tree, hf_tcpclv3_pkt_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1289 msgtype_name = val_to_str_const((conv_hdr>>4)&0xF, v3_message_type_vals, "Unknown");
1290 col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, msgtype_name);
1291 proto_item_append_text(proto_tree_get_parent(conv_tree), ": %s", msgtype_name);
1293 switch (conv_hdr & TCPCLV3_TYPE_MASK) {
1294 case TCPCLV3_DATA_SEGMENT: {
1295 proto_item *item_flags;
1297 item_flags = proto_tree_add_bitmask(
1298 conv_tree, tvb,
1299 offset, hf_tcpclv3_data_procflags,
1300 ett_tcpclv3_data_procflags, v3_data_procflags,
1301 ENC_BIG_ENDIAN
1303 offset += 1;
1305 /* Only Start and End flags (bits 0 & 1) are valid in Data Segment */
1306 if ((conv_hdr & ~(TCPCLV3_TYPE_MASK | TCPCLV3_DATA_FLAGS)) != 0) {
1307 expert_add_info(pinfo, item_flags, &ei_tcpclv3_data_flags);
1310 sub_item = proto_tree_add_item_ret_varint(conv_tree, hf_tcpclv3_data_segment_length, tvb, offset, -1, ENC_VARINT_SDNV, &segment_length, &sdnv_length);
1311 if (sdnv_length == 0) {
1312 expert_add_info(pinfo, sub_item, &ei_tcpclv3_segment_length);
1313 return 0;
1315 offset += sdnv_length;
1316 const int data_len_clamp = get_clamped_length(segment_length, pinfo, sub_item);
1318 // implied transfer ID
1319 xfer_id = wmem_map_lookup(ctx->tx_peer->frame_loc_to_transfer, ctx->cur_loc);
1320 if (!xfer_id) {
1321 xfer_id = wmem_new(wmem_packet_scope(), uint64_t);
1322 *xfer_id = wmem_map_size(ctx->tx_peer->transfers);
1324 if (conv_hdr & TCPCLV3_DATA_START_FLAG) {
1325 *xfer_id += 1;
1326 get_or_create_transfer_t(ctx->tx_peer->transfers, *xfer_id);
1328 tcpcl_peer_associate_transfer(ctx->tx_peer, ctx->cur_loc, *xfer_id);
1330 item_xfer_id = proto_tree_add_uint64(conv_tree, hf_tcpclv3_xfer_id, tvb, 0, 0, *xfer_id);
1331 proto_item_set_generated(item_xfer_id);
1333 proto_tree_add_item(conv_tree, hf_tcpclv3_data_segment_data, tvb, offset, data_len_clamp, ENC_NA);
1335 if (tcpcl_analyze_sequence) {
1336 transfer_add_segment(ctx, *xfer_id, (conv_hdr & TCPCLV3_DATA_FLAGS), segment_length, pinfo, tvb, conv_tree, conv_item, item_flags);
1339 if (tcpcl_desegment_transfer) {
1340 // Reassemble the segments
1341 fragment_head *frag_msg;
1342 frag_msg = fragment_add_seq_next(
1343 &xfer_reassembly_table,
1344 tvb, offset,
1345 pinfo, 0, xfer_id,
1346 data_len_clamp,
1347 !(conv_hdr & TCPCLV3_DATA_END_FLAG)
1349 ctx->xferload = process_reassembled_data(
1350 tvb, offset, pinfo,
1351 "Reassembled Transfer",
1352 frag_msg,
1353 &xfer_frag_items,
1354 NULL,
1355 proto_tree_get_parent_tree(tree)
1358 offset += data_len_clamp;
1360 break;
1362 case TCPCLV3_ACK_SEGMENT: {
1363 /*No valid flags*/
1364 offset += 1;
1366 sub_item = proto_tree_add_item_ret_varint(conv_tree, hf_tcpclv3_ack_length, tvb, offset, -1, ENC_VARINT_SDNV, &segment_length, &sdnv_length);
1367 if (sdnv_length == 0) {
1368 expert_add_info(pinfo, sub_item, &ei_tcpclv3_ack_length);
1369 } else {
1370 offset += sdnv_length;
1373 // implied transfer ID
1374 xfer_id = wmem_map_lookup(ctx->rx_peer->frame_loc_to_transfer, ctx->cur_loc);
1375 if (!xfer_id) {
1376 xfer_id = wmem_new(wmem_packet_scope(), uint64_t);
1377 *xfer_id = wmem_map_size(ctx->rx_peer->transfers);
1379 tcpcl_peer_associate_transfer(ctx->rx_peer, ctx->cur_loc, *xfer_id);
1381 item_xfer_id = proto_tree_add_uint64(conv_tree, hf_tcpclv3_xfer_id, tvb, 0, 0, *xfer_id);
1382 proto_item_set_generated(item_xfer_id);
1384 if (tcpcl_analyze_sequence) {
1385 transfer_add_ack(ctx, *xfer_id, 0, segment_length, pinfo, tvb, conv_tree, conv_item, NULL);
1388 break;
1390 case TCPCLV3_KEEP_ALIVE:
1391 /*No valid flags in Keep Alive*/
1392 offset += 1;
1393 break;
1395 case TCPCLV3_SHUTDOWN:
1396 /* Add tree for Shutdown Flags */
1397 sub_item = proto_tree_add_item(conv_tree, hf_tcpclv3_shutdown_flags, tvb,
1398 offset, 1, ENC_BIG_ENDIAN);
1399 sub_tree = proto_item_add_subtree(sub_item, ett_tcpclv3_shutdown_flags);
1401 proto_tree_add_item(sub_tree, hf_tcpclv3_shutdown_flags_reason,
1402 tvb, offset, 1, ENC_BIG_ENDIAN);
1403 proto_tree_add_item(sub_tree, hf_tcpclv3_shutdown_flags_delay,
1404 tvb, offset, 1, ENC_BIG_ENDIAN);
1406 offset += 1;
1407 if (conv_hdr & TCPCLV3_SHUTDOWN_REASON) {
1408 proto_tree_add_item(conv_tree,
1409 hf_tcpclv3_shutdown_reason, tvb,
1410 offset, 1, ENC_BIG_ENDIAN);
1411 offset += 1;
1413 if (conv_hdr & TCPCLV3_SHUTDOWN_DELAY) {
1414 proto_tree_add_item(conv_tree,
1415 hf_tcpclv3_shutdown_delay, tvb,
1416 offset, 2, ENC_BIG_ENDIAN);
1417 offset += 1;
1419 break;
1420 case TCPCLV3_REFUSE_BUNDLE:
1421 /*No valid flags*/
1422 offset += 1;
1424 refuse_bundle_hdr = tvb_get_uint8(tvb, offset);
1425 proto_tree_add_item(conv_tree, hf_tcpclv3_refuse_reason_code, tvb, offset, 1, ENC_BIG_ENDIAN);
1426 offset += 1;
1427 col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const((refuse_bundle_hdr>>4)&0xF, v3_refuse_reason_code, "Unknown"));
1429 // implied transfer ID
1430 xfer_id = wmem_map_lookup(ctx->rx_peer->frame_loc_to_transfer, ctx->cur_loc);
1431 if (!xfer_id) {
1432 xfer_id = wmem_new(wmem_packet_scope(), uint64_t);
1433 *xfer_id = wmem_map_size(ctx->rx_peer->transfers);
1435 tcpcl_peer_associate_transfer(ctx->rx_peer, ctx->cur_loc, *xfer_id);
1437 item_xfer_id = proto_tree_add_uint64(conv_tree, hf_tcpclv3_xfer_id, tvb, 0, 0, *xfer_id);
1438 proto_item_set_generated(item_xfer_id);
1440 if (tcpcl_analyze_sequence) {
1441 transfer_add_refuse(ctx, *xfer_id, pinfo, tvb, conv_tree, conv_item);
1444 break;
1446 default:
1447 expert_add_info(pinfo, proto_tree_get_parent(conv_tree), &ei_tcpclv3_invalid_msg_type);
1448 break;
1451 return offset;
1454 static unsigned get_v4_msg_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset,
1455 tcpcl_dissect_ctx_t *ctx _U_) {
1456 const int init_offset = offset;
1457 uint8_t msgtype = tvb_get_uint8(tvb, offset);
1458 offset += 1;
1459 switch(msgtype) {
1460 case TCPCLV4_MSGTYPE_SESS_INIT: {
1461 const int buflen = tvb_reported_length(tvb);
1462 offset += 2 + 8 + 8;
1463 if (buflen < offset + 2) {
1464 return 0;
1466 uint16_t nodeid_len = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
1467 offset += 2;
1468 offset += nodeid_len;
1469 if (buflen < offset + 4) {
1470 return 0;
1472 uint32_t extlist_len = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
1473 offset += 4;
1474 offset += extlist_len;
1475 break;
1477 case TCPCLV4_MSGTYPE_SESS_TERM: {
1478 offset += 1 + 1;
1479 break;
1481 case TCPCLV4_MSGTYPE_XFER_SEGMENT: {
1482 const int buflen = tvb_reported_length(tvb);
1483 if (buflen < offset + 1) {
1484 return 0;
1486 uint8_t flags = tvb_get_uint8(tvb, offset);
1487 offset += 1;
1488 offset += 8;
1489 if (flags & TCPCLV4_TRANSFER_FLAG_START) {
1490 if (buflen < offset + 4) {
1491 return 0;
1493 uint32_t extlist_len = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
1494 offset += 4;
1495 offset += extlist_len;
1497 if (buflen < offset + 8) {
1498 return 0;
1500 uint64_t data_len = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
1501 offset += 8;
1502 const int data_len_clamp = get_clamped_length(data_len, NULL, NULL);
1503 offset += data_len_clamp;
1504 break;
1506 case TCPCLV4_MSGTYPE_XFER_ACK: {
1507 offset += 1 + 8 + 8;
1508 break;
1510 case TCPCLV4_MSGTYPE_XFER_REFUSE: {
1511 offset += 1 + 8;
1512 break;
1514 case TCPCLV4_MSGTYPE_KEEPALIVE: {
1515 break;
1517 case TCPCLV4_MSGTYPE_MSG_REJECT: {
1518 offset += 1 + 1;
1519 break;
1521 default:
1522 // no known message
1523 return 0;
1525 return offset - init_offset;
1528 static int
1529 dissect_v4_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1530 tcpcl_dissect_ctx_t *ctx _U_) {
1531 int offset = 0;
1532 // Length of non-protocol 'payload' data in this message
1533 int payload_len = 0;
1535 uint8_t msgtype = 0;
1536 const char *msgtype_name = NULL;
1538 proto_item *item_msg = proto_tree_add_item(tree, hf_tcpclv4_mhdr_tree, tvb, offset, 0, ENC_NA);
1539 proto_tree *tree_msg = proto_item_add_subtree(item_msg, ett_tcpclv4_mhdr);
1541 msgtype = tvb_get_uint8(tvb, offset);
1542 proto_tree_add_uint(tree_msg, hf_tcpclv4_mhdr_type, tvb, offset, 1, msgtype);
1543 offset += 1;
1544 msgtype_name = val_to_str(msgtype, v4_message_type_vals, "type 0x%02" PRIx32);
1545 wmem_strbuf_t *suffix_text = wmem_strbuf_new(wmem_packet_scope(), NULL);
1547 switch(msgtype) {
1548 case TCPCLV4_MSGTYPE_SESS_INIT: {
1549 uint16_t keepalive = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
1550 proto_tree_add_uint(tree_msg, hf_tcpclv4_sess_init_keepalive, tvb, offset, 2, keepalive);
1551 offset += 2;
1553 uint64_t seg_mru = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
1554 proto_tree_add_uint64(tree_msg, hf_tcpclv4_sess_init_seg_mru, tvb, offset, 8, seg_mru);
1555 offset += 8;
1557 uint64_t xfer_mru = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
1558 proto_tree_add_uint64(tree_msg, hf_tcpclv4_sess_init_xfer_mru, tvb, offset, 8, xfer_mru);
1559 offset += 8;
1561 uint16_t nodeid_len = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
1562 proto_tree_add_uint(tree_msg, hf_tcpclv4_sess_init_nodeid_len, tvb, offset, 2, nodeid_len);
1563 offset += 2;
1566 uint8_t *nodeid_data = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, nodeid_len, ENC_UTF_8);
1567 proto_tree_add_string(tree_msg, hf_tcpclv4_sess_init_nodeid_data, tvb, offset, nodeid_len, (const char *)nodeid_data);
1568 wmem_free(wmem_packet_scope(), nodeid_data);
1570 offset += nodeid_len;
1572 uint32_t extlist_len = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
1573 proto_tree_add_uint(tree_msg, hf_tcpclv4_sess_init_extlist_len, tvb, offset, 4, extlist_len);
1574 offset += 4;
1576 int extlist_offset = 0;
1577 while (extlist_offset < (int)extlist_len) {
1578 int extitem_offset = 0;
1579 proto_item *item_ext = proto_tree_add_item(tree_msg, hf_tcpclv4_sessext_tree, tvb, offset + extlist_offset, 0, ENC_NA);
1580 proto_tree *tree_ext = proto_item_add_subtree(item_ext, ett_tcpclv4_sessext);
1582 uint8_t extitem_flags = tvb_get_uint8(tvb, offset + extlist_offset + extitem_offset);
1583 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_ENDIAN);
1584 extitem_offset += 1;
1585 const bool is_critical = (extitem_flags & TCPCLV4_EXTENSION_FLAG_CRITICAL);
1586 if (is_critical) {
1587 expert_add_info(pinfo, item_ext, &ei_tcpclv4_extitem_critical);
1590 uint16_t extitem_type = tvb_get_uint16(tvb, offset + extlist_offset + extitem_offset, ENC_BIG_ENDIAN);
1591 proto_item *item_type = proto_tree_add_uint(tree_ext, hf_tcpclv4_sessext_type, tvb, offset + extlist_offset + extitem_offset, 2, extitem_type);
1592 extitem_offset += 2;
1594 dissector_handle_t subdis = dissector_get_uint_handle(xfer_ext_dissectors, extitem_type);
1595 const char *subname = dissector_handle_get_description(subdis);
1596 if (subdis) {
1597 proto_item_set_text(item_type, "Item Type: %s (0x%04" PRIx16 ")", subname, extitem_type);
1600 uint16_t extitem_len = tvb_get_uint16(tvb, offset + extlist_offset + extitem_offset, ENC_BIG_ENDIAN);
1601 proto_tree_add_uint(tree_ext, hf_tcpclv4_sessext_len, tvb, offset + extlist_offset + extitem_offset, 2, extitem_len);
1602 extitem_offset += 2;
1604 tvbuff_t *extitem_tvb = tvb_new_subset_length(tvb, offset + extlist_offset + extitem_offset, extitem_len);
1605 proto_item *item_extdata = proto_tree_add_item(tree_ext, hf_tcpclv4_sessext_data, extitem_tvb, 0, tvb_captured_length(extitem_tvb), ENC_NA);
1606 proto_tree *tree_extdata = proto_item_add_subtree(item_extdata, ett_tcpclv4_sessext_data);
1608 int sublen = 0;
1609 if (subdis) {
1610 sublen = call_dissector_only(subdis, extitem_tvb, pinfo, tree_extdata, NULL);
1612 if (sublen == 0) {
1613 expert_add_info(pinfo, item_type, &ei_tcpclv4_invalid_sessext_type);
1615 extitem_offset += extitem_len;
1617 proto_item_set_len(item_ext, extitem_offset);
1618 extlist_offset += extitem_offset;
1620 if (subname) {
1621 proto_item_append_text(item_ext, ": %s", subname);
1623 else {
1624 proto_item_append_text(item_ext, ": Type 0x%04" PRIx16, extitem_type);
1626 if (is_critical) {
1627 proto_item_append_text(item_ext, ", CRITICAL");
1630 // advance regardless of any internal offset processing
1631 offset += extlist_len;
1633 if (ctx->tx_peer->sess_init_seen) {
1634 if (tcpcl_analyze_sequence) {
1635 if (!tcpcl_frame_loc_equal(ctx->tx_peer->sess_init_seen, ctx->cur_loc)) {
1636 expert_add_info(pinfo, item_msg, &ei_tcpclv4_sess_init_duplicate);
1640 else {
1641 ctx->tx_peer->sess_init_seen = tcpcl_frame_loc_clone(wmem_file_scope(), ctx->cur_loc);
1642 ctx->tx_peer->keepalive = keepalive;
1643 ctx->tx_peer->segment_mru = seg_mru;
1644 ctx->tx_peer->transfer_mru = xfer_mru;
1647 break;
1649 case TCPCLV4_MSGTYPE_SESS_TERM: {
1650 uint8_t flags = tvb_get_uint8(tvb, offset);
1651 proto_tree_add_bitmask(tree_msg, tvb, offset, hf_tcpclv4_sess_term_flags, ett_tcpclv4_sess_term_flags, v4_sess_term_flags, ENC_BIG_ENDIAN);
1652 offset += 1;
1654 uint8_t reason = tvb_get_uint8(tvb, offset);
1655 proto_tree_add_uint(tree_msg, hf_tcpclv4_sess_term_reason, tvb, offset, 1, reason);
1656 offset += 1;
1658 if (ctx->tx_peer->sess_term_seen) {
1659 if (tcpcl_analyze_sequence) {
1660 if (!tcpcl_frame_loc_equal(ctx->tx_peer->sess_term_seen, ctx->cur_loc)) {
1661 expert_add_info(pinfo, item_msg, &ei_tcpclv4_sess_term_duplicate);
1665 else {
1666 ctx->tx_peer->sess_term_seen = tcpcl_frame_loc_clone(wmem_file_scope(), ctx->cur_loc);
1667 ctx->tx_peer->sess_term_reason = reason;
1670 if (tcpcl_analyze_sequence) {
1671 if (ctx->rx_peer->sess_term_seen) {
1672 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);
1673 proto_item_set_generated(item_rel);
1675 // Is this message after the other SESS_TERM?
1676 if (tcpcl_frame_loc_compare(ctx->tx_peer->sess_term_seen, ctx->rx_peer->sess_term_seen, NULL) > 0) {
1677 if (!(flags & TCPCLV4_SESS_TERM_FLAG_REPLY)) {
1678 expert_add_info(pinfo, item_msg, &ei_tcpclv4_sess_term_reply_flag);
1684 break;
1686 case TCPCLV4_MSGTYPE_XFER_SEGMENT:{
1687 uint8_t flags = tvb_get_uint8(tvb, offset);
1688 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_ENDIAN);
1689 offset += 1;
1691 uint64_t xfer_id = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
1692 proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_id, tvb, offset, 8, xfer_id);
1693 offset += 8;
1695 if (flags & TCPCLV4_TRANSFER_FLAG_START) {
1696 uint32_t extlist_len = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
1697 proto_tree_add_uint(tree_msg, hf_tcpclv4_xfer_segment_extlist_len, tvb, offset, 4, extlist_len);
1698 offset += 4;
1700 int extlist_offset = 0;
1701 while (extlist_offset < (int)extlist_len) {
1702 int extitem_offset = 0;
1703 proto_item *item_ext = proto_tree_add_item(tree_msg, hf_tcpclv4_xferext_tree, tvb, offset + extlist_offset, 0, ENC_NA);
1704 proto_tree *tree_ext = proto_item_add_subtree(item_ext, ett_tcpclv4_xferext);
1706 uint8_t extitem_flags = tvb_get_uint8(tvb, offset + extlist_offset + extitem_offset);
1707 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_ENDIAN);
1708 extitem_offset += 1;
1709 const bool is_critical = (extitem_flags & TCPCLV4_EXTENSION_FLAG_CRITICAL);
1710 if (is_critical) {
1711 expert_add_info(pinfo, item_ext, &ei_tcpclv4_extitem_critical);
1714 uint16_t extitem_type = tvb_get_uint16(tvb, offset + extlist_offset + extitem_offset, ENC_BIG_ENDIAN);
1715 proto_item *item_type = proto_tree_add_uint(tree_ext, hf_tcpclv4_xferext_type, tvb, offset + extlist_offset + extitem_offset, 2, extitem_type);
1716 extitem_offset += 2;
1718 dissector_handle_t subdis = dissector_get_uint_handle(xfer_ext_dissectors, extitem_type);
1719 const char *subname = dissector_handle_get_description(subdis);
1720 if (subdis) {
1721 proto_item_set_text(item_type, "Item Type: %s (0x%04" PRIx16 ")", subname, extitem_type);
1724 uint16_t extitem_len = tvb_get_uint16(tvb, offset + extlist_offset + extitem_offset, ENC_BIG_ENDIAN);
1725 proto_tree_add_uint(tree_ext, hf_tcpclv4_xferext_len, tvb, offset + extlist_offset + extitem_offset, 2, extitem_len);
1726 extitem_offset += 2;
1728 tvbuff_t *extitem_tvb = tvb_new_subset_length(tvb, offset + extlist_offset + extitem_offset, extitem_len);
1729 proto_item *item_extdata = proto_tree_add_item(tree_ext, hf_tcpclv4_xferext_data, extitem_tvb, 0, tvb_captured_length(extitem_tvb), ENC_NA);
1730 proto_tree *tree_extdata = proto_item_add_subtree(item_extdata, ett_tcpclv4_xferext_data);
1732 tcpcl_frame_loc_t *extitem_loc = tcpcl_frame_loc_new(wmem_packet_scope(), pinfo, extitem_tvb, 0);
1733 tcpcl_peer_associate_transfer(ctx->tx_peer, extitem_loc, xfer_id);
1735 int sublen = 0;
1736 if (subdis) {
1737 sublen = call_dissector_only(subdis, extitem_tvb, pinfo, tree_extdata, NULL);
1739 if (sublen == 0) {
1740 expert_add_info(pinfo, item_type, &ei_tcpclv4_invalid_xferext_type);
1742 extitem_offset += extitem_len;
1744 proto_item_set_len(item_ext, extitem_offset);
1745 extlist_offset += extitem_offset;
1747 if (subname) {
1748 proto_item_append_text(item_ext, ": %s", subname);
1750 else {
1751 proto_item_append_text(item_ext, ": Type 0x%04" PRIx16, extitem_type);
1753 if (is_critical) {
1754 proto_item_append_text(item_ext, ", CRITICAL");
1757 // advance regardless of any internal offset processing
1758 offset += extlist_len;
1761 uint64_t data_len = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
1762 proto_item *item_len = proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_segment_data_len, tvb, offset, 8, data_len);
1763 offset += 8;
1765 if (data_len > ctx->rx_peer->segment_mru) {
1766 expert_add_info(pinfo, item_len, &ei_tcpclv4_xfer_seg_over_seg_mru);
1768 const int data_len_clamp = get_clamped_length(data_len, pinfo, item_len);
1770 // Treat data as payload layer
1771 const int data_offset = offset;
1772 proto_tree_add_item(tree_msg, hf_tcpclv4_xfer_segment_data, tvb, offset, data_len_clamp, ENC_NA);
1773 offset += data_len_clamp;
1774 payload_len = data_len_clamp;
1776 wmem_strbuf_append_printf(suffix_text, ", Xfer ID: %" PRIi64, xfer_id);
1778 if (flags) {
1779 wmem_strbuf_append(suffix_text, ", Flags: ");
1780 bool sep = false;
1781 if (flags & TCPCLV4_TRANSFER_FLAG_START) {
1782 wmem_strbuf_append(suffix_text, "START");
1783 sep = true;
1785 if (flags & TCPCLV4_TRANSFER_FLAG_END) {
1786 if (sep) {
1787 wmem_strbuf_append(suffix_text, "|");
1789 wmem_strbuf_append(suffix_text, "END");
1793 if (tcpcl_analyze_sequence) {
1794 transfer_add_segment(ctx, xfer_id, flags, data_len, pinfo, tvb, tree_msg, item_msg, item_flags);
1797 if (tcpcl_desegment_transfer) {
1798 // Reassemble the segments
1799 fragment_head *xferload_frag_msg = fragment_add_seq_next(
1800 &xfer_reassembly_table,
1801 tvb, data_offset,
1802 pinfo, 0, &xfer_id,
1803 data_len_clamp,
1804 !(flags & TCPCLV4_TRANSFER_FLAG_END)
1806 ctx->xferload = process_reassembled_data(
1807 tvb, data_offset, pinfo,
1808 "Reassembled Transfer",
1809 xferload_frag_msg,
1810 &xfer_frag_items,
1811 NULL,
1812 proto_tree_get_parent_tree(tree)
1816 break;
1818 case TCPCLV4_MSGTYPE_XFER_ACK:{
1819 uint8_t flags = tvb_get_uint8(tvb, offset);
1820 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_ENDIAN);
1821 offset += 1;
1823 uint64_t xfer_id = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
1824 proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_id, tvb, offset, 8, xfer_id);
1825 offset += 8;
1827 uint64_t ack_len = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
1828 proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_ack_ack_len, tvb, offset, 8, ack_len);
1829 offset += 8;
1831 wmem_strbuf_append_printf(suffix_text, ", Xfer ID: %" PRIi64, xfer_id);
1833 if (flags) {
1834 wmem_strbuf_append(suffix_text, ", Flags: ");
1835 bool sep = false;
1836 if (flags & TCPCLV4_TRANSFER_FLAG_START) {
1837 wmem_strbuf_append(suffix_text, "START");
1838 sep = true;
1840 if (flags & TCPCLV4_TRANSFER_FLAG_END) {
1841 if (sep) {
1842 wmem_strbuf_append(suffix_text, "|");
1844 wmem_strbuf_append(suffix_text, "END");
1848 if (tcpcl_analyze_sequence) {
1849 transfer_add_ack(ctx, xfer_id, flags, ack_len, pinfo, tvb, tree_msg, item_msg, item_flags);
1852 break;
1854 case TCPCLV4_MSGTYPE_XFER_REFUSE: {
1855 uint8_t reason = tvb_get_uint8(tvb, offset);
1856 proto_tree_add_uint(tree_msg, hf_tcpclv4_xfer_refuse_reason, tvb, offset, 1, reason);
1857 offset += 1;
1859 uint64_t xfer_id = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
1860 proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_id, tvb, offset, 8, xfer_id);
1861 offset += 8;
1863 wmem_strbuf_append_printf(suffix_text, ", Xfer ID: %" PRIi64, xfer_id);
1865 if (tcpcl_analyze_sequence) {
1866 transfer_add_refuse(ctx, xfer_id, pinfo, tvb, tree_msg, item_msg);
1869 break;
1871 case TCPCLV4_MSGTYPE_KEEPALIVE: {
1872 break;
1874 case TCPCLV4_MSGTYPE_MSG_REJECT: {
1875 uint8_t reason = tvb_get_uint8(tvb, offset);
1876 proto_tree_add_uint(tree_msg, hf_tcpclv4_msg_reject_reason, tvb, offset, 1, reason);
1877 offset += 1;
1879 uint8_t rej_head = tvb_get_uint8(tvb, offset);
1880 proto_tree_add_uint(tree_msg, hf_tcpclv4_msg_reject_head, tvb, offset, 1, rej_head);
1881 offset += 1;
1883 break;
1885 default:
1886 expert_add_info(pinfo, item_msg, &ei_tcpclv4_invalid_msg_type);
1887 break;
1890 proto_item_set_len(item_msg, offset - payload_len);
1891 proto_item_append_text(item_msg, ": %s%s", msgtype_name, wmem_strbuf_get_str(suffix_text));
1892 wmem_strbuf_finalize(suffix_text);
1894 if (tcpcl_analyze_sequence) {
1895 if (!(ctx->tx_peer->chdr_missing)) {
1896 // assume the capture is somewhere in the middle
1897 if (!(ctx->tx_peer->sess_init_seen)) {
1898 expert_add_info(pinfo, item_msg, &ei_tcpclv4_sess_init_missing);
1900 else {
1901 // This message is before SESS_INIT (but is not the SESS_INIT)
1902 const int cmp_sess_init = tcpcl_frame_loc_compare(ctx->cur_loc, ctx->tx_peer->sess_init_seen, NULL);
1903 if (((msgtype == TCPCLV4_MSGTYPE_SESS_INIT) && (cmp_sess_init < 0))
1904 || ((msgtype != TCPCLV4_MSGTYPE_SESS_INIT) && (cmp_sess_init <= 0))) {
1905 expert_add_info(pinfo, item_msg, &ei_tcpclv4_sess_init_missing);
1911 if (msgtype_name) {
1912 col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, msgtype_name);
1915 try_negotiate(ctx, pinfo);
1916 // Show negotiation results
1917 if (msgtype == TCPCLV4_MSGTYPE_SESS_INIT) {
1918 if (ctx->convo->sess_negotiated) {
1919 if (ctx->rx_peer->sess_init_seen){
1920 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);
1921 proto_item_set_generated(item_nego);
1924 proto_item *item_nego = proto_tree_add_uint(tree_msg, hf_tcpclv4_negotiate_keepalive, tvb, 0, 0, ctx->convo->sess_keepalive);
1925 proto_item_set_generated(item_nego);
1930 return offset;
1933 /** Function to extract a message length, or zero if not valid.
1934 * This will call set_chdr_missing() if valid.
1936 typedef unsigned (*chdr_missing_check)(packet_info *, tvbuff_t *, int offset, tcpcl_dissect_ctx_t *);
1938 /** Inspect a single segment to determine if this looks like a TLS record set.
1940 static unsigned chdr_missing_tls(packet_info *pinfo, tvbuff_t *tvb, int offset,
1941 tcpcl_dissect_ctx_t *ctx) {
1942 if (ctx->convo->session_tls_start) {
1943 // already in a TLS context
1944 return 0;
1947 // similar heuristics to is_sslv3_or_tls() from packet-tls.c
1948 if (tvb_captured_length(tvb) < 5) {
1949 return 0;
1951 uint8_t rectype = tvb_get_uint8(tvb, offset);
1952 uint16_t recvers = tvb_get_uint16(tvb, offset+1, ENC_BIG_ENDIAN);
1953 uint16_t reclen = tvb_get_uint16(tvb, offset+1+2, ENC_BIG_ENDIAN);
1955 switch(rectype) {
1956 // These overlap with TCPCLV3_DATA_SEGMENT but have invalid flags
1957 // They are valid but unallocated v4 message type codes
1958 case SSL_ID_ALERT:
1959 case SSL_ID_HANDSHAKE:
1960 case SSL_ID_APP_DATA:
1961 case SSL_ID_HEARTBEAT:
1962 break;
1963 default:
1964 return 0;
1966 if ((recvers & 0xFF00) != 0x0300) {
1967 return 0;
1969 if (reclen == 0 || reclen >= TLS_MAX_RECORD_LENGTH + 2048) {
1970 return 0;
1973 // post-STARTTLS
1974 ctx->convo->session_use_tls = true;
1975 ctx->convo->session_tls_start = tcpcl_frame_loc_clone(wmem_file_scope(), ctx->cur_loc);
1976 ssl_starttls_post_ack(tls_handle, pinfo, tcpcl_handle);
1978 return tvb_reported_length(tvb);
1982 static unsigned chdr_missing_v3(packet_info *pinfo, tvbuff_t *tvb, int offset,
1983 tcpcl_dissect_ctx_t *ctx) {
1984 unsigned sublen = get_v3_msg_len(pinfo, tvb, offset, ctx);
1985 if (sublen > 0) {
1986 set_chdr_missing(ctx->tx_peer, 3);
1988 return sublen;
1991 static unsigned chdr_missing_v4(packet_info *pinfo, tvbuff_t *tvb, int offset,
1992 tcpcl_dissect_ctx_t *ctx) {
1993 unsigned sublen = get_v4_msg_len(pinfo, tvb, offset, ctx);
1994 if (sublen > 0) {
1995 set_chdr_missing(ctx->tx_peer, 4);
1997 return sublen;
2000 static const chdr_missing_check chdr_missing_v3first[] = {
2001 &chdr_missing_tls,
2002 &chdr_missing_v3,
2003 &chdr_missing_v4,
2004 NULL
2006 static const chdr_missing_check chdr_missing_v3only[] = {
2007 &chdr_missing_v3,
2008 NULL
2010 static const chdr_missing_check chdr_missing_v4first[] = {
2011 &chdr_missing_tls,
2012 &chdr_missing_v4,
2013 &chdr_missing_v3,
2014 NULL
2016 static const chdr_missing_check chdr_missing_v4only[] = {
2017 &chdr_missing_v4,
2018 NULL
2021 static unsigned get_message_len(packet_info *pinfo, tvbuff_t *tvb, int ext_offset, void *data _U_) {
2022 tcpcl_dissect_ctx_t *ctx = tcpcl_dissect_ctx_get(tvb, pinfo, ext_offset);
2023 if (!ctx) {
2024 return 0;
2026 const unsigned init_offset = ext_offset;
2027 unsigned offset = ext_offset;
2029 if (ctx->is_contact) {
2030 if (tvb_memeql(tvb, offset, magic, sizeof(magic)) != 0) {
2031 // Optional heuristic dissection of a message
2032 const chdr_missing_check *checks = NULL;
2033 switch (tcpcl_chdr_missing) {
2034 case CHDRMSN_V3FIRST:
2035 checks = chdr_missing_v3first;
2036 break;
2037 case CHDRMSN_V3ONLY:
2038 checks = chdr_missing_v3only;
2039 break;
2040 case CHDRMSN_V4FIRST:
2041 checks = chdr_missing_v4first;
2042 break;
2043 case CHDRMSN_V4ONLY:
2044 checks = chdr_missing_v4only;
2045 break;
2047 if (checks) {
2048 for (const chdr_missing_check *chk = checks; *chk; ++chk) {
2049 unsigned sublen = (**chk)(pinfo, tvb, offset, ctx);
2050 if (sublen > 0) {
2051 return sublen;
2054 // no match
2055 return 0;
2057 else {
2058 // require the contact header
2059 const unsigned available = tvb_captured_length(tvb) - offset;
2060 if (available < sizeof(magic) + 1) {
2061 return DESEGMENT_ONE_MORE_SEGMENT;
2063 // sufficient size available but no match
2064 return 0;
2067 offset += sizeof(magic);
2069 uint8_t version = tvb_get_uint8(tvb, offset);
2070 offset += 1;
2071 if (version == 3) {
2072 offset += 3; // flags + keepalive
2073 uint64_t eid_len;
2074 const unsigned bytecount = tvb_get_sdnv(tvb, offset, &eid_len);
2075 const int len_clamp = get_clamped_length(eid_len, NULL, NULL);
2076 offset += bytecount + len_clamp;
2078 else if (version == 4) {
2079 offset += 1; // flags
2081 else {
2082 return 0;
2085 else {
2086 if (ctx->tx_peer->version == 3) {
2087 unsigned sublen = get_v3_msg_len(pinfo, tvb, offset, ctx);
2088 if (sublen == 0) {
2089 return 0;
2091 offset += sublen;
2093 else if (ctx->tx_peer->version == 4) {
2094 unsigned sublen = get_v4_msg_len(pinfo, tvb, offset, ctx);
2095 if (sublen == 0) {
2096 return 0;
2098 offset += sublen;
2100 else {
2101 return 0;
2104 const int needlen = offset - init_offset;
2105 return needlen;
2108 static int dissect_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
2109 int offset = 0;
2110 tcpcl_dissect_ctx_t *ctx = tcpcl_dissect_ctx_get(tvb, pinfo, offset);
2111 if (!ctx) {
2112 return 0;
2116 const char *proto_name = col_get_text(pinfo->cinfo, COL_PROTOCOL);
2117 if (g_strcmp0(proto_name, proto_name_tcpcl) != 0) {
2118 col_set_str(pinfo->cinfo, COL_PROTOCOL, proto_name_tcpcl);
2119 col_clear(pinfo->cinfo, COL_INFO);
2123 // Don't add more than one TCPCL tree item
2124 proto_item *item_tcpcl;
2125 proto_tree *tree_tcpcl;
2126 if (tree && (tree->last_child)
2127 && (PITEM_HFINFO(tree->last_child)->id == proto_tcpcl)) {
2128 item_tcpcl = tree->last_child;
2129 tree_tcpcl = proto_item_get_subtree(item_tcpcl);
2131 else {
2132 item_tcpcl = proto_tree_add_item(tree, proto_tcpcl, tvb, 0, 0, ENC_NA);
2133 tree_tcpcl = proto_item_add_subtree(item_tcpcl, ett_proto_tcpcl);
2136 if (ctx->tx_peer->chdr_missing) {
2137 expert_add_info(pinfo, item_tcpcl, &ei_chdr_missing);
2139 if (ctx->is_contact) {
2140 col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "Contact Header");
2142 proto_item *item_chdr = proto_tree_add_item(tree_tcpcl, hf_chdr_tree, tvb, offset, -1, ENC_NA);
2143 proto_tree *tree_chdr = proto_item_add_subtree(item_chdr, ett_chdr);
2145 proto_item *item_magic = proto_tree_add_item(tree_chdr, hf_chdr_magic, tvb, offset, sizeof(magic), ENC_SEP_NONE);
2146 if (tvb_memeql(tvb, offset, magic, sizeof(magic)) != 0) {
2147 expert_add_info(pinfo, item_magic, &ei_invalid_magic);
2148 return 0;
2150 offset += sizeof(magic);
2152 ctx->tx_peer->version = tvb_get_uint8(tvb, offset);
2153 proto_item *item_version = proto_tree_add_uint(tree_chdr, hf_chdr_version, tvb, offset, 1, ctx->tx_peer->version);
2154 offset += 1;
2156 // Mark or check version match
2157 if (!ctx->convo->version) {
2158 ctx->convo->version = wmem_new(wmem_file_scope(), uint8_t);
2159 *(ctx->convo->version) = ctx->tx_peer->version;
2161 else if (*(ctx->convo->version) != ctx->tx_peer->version) {
2162 expert_add_info(pinfo, item_version, &ei_mismatch_version);
2165 if ((ctx->tx_peer->version < 3) || (ctx->tx_peer->version > 4)) {
2166 expert_add_info(pinfo, item_version, &ei_invalid_version);
2167 return offset;
2170 if (ctx->tx_peer->version == 3) {
2171 /* Subtree to expand the bits in the Contact Header Flags */
2172 proto_tree_add_bitmask(tree_chdr, tvb, offset, hf_tcpclv3_chdr_flags, ett_tcpclv3_chdr_flags, v3_chdr_flags, ENC_BIG_ENDIAN);
2173 offset++;
2175 proto_tree_add_item(tree_chdr, hf_tcpclv3_chdr_keep_alive, tvb, offset, 2, ENC_BIG_ENDIAN);
2176 offset += 2;
2179 * New format Contact header has length field followed by EID.
2181 uint64_t eid_length;
2182 int sdnv_length;
2183 proto_item *sub_item = proto_tree_add_item_ret_varint(tree_chdr, hf_tcpclv3_chdr_local_eid_length, tvb, offset, -1, ENC_VARINT_SDNV, &eid_length, &sdnv_length);
2184 if (sdnv_length == 0) {
2185 expert_add_info(pinfo, sub_item, &ei_tcpclv3_eid_length);
2186 return 0;
2188 offset += sdnv_length;
2189 const int eid_len_clamp = get_clamped_length(eid_length, pinfo, sub_item);
2191 proto_tree_add_item(tree_chdr, hf_tcpclv3_chdr_local_eid, tvb, offset, eid_len_clamp, ENC_NA|ENC_ASCII);
2192 offset += eid_len_clamp;
2194 // assumed parameters
2195 ctx->tx_peer->segment_mru = UINT64_MAX;
2196 ctx->tx_peer->transfer_mru = UINT64_MAX;
2198 else if (ctx->tx_peer->version == 4) {
2199 uint8_t flags = tvb_get_uint8(tvb, offset);
2200 proto_tree_add_bitmask(tree_chdr, tvb, offset, hf_tcpclv4_chdr_flags, ett_tcpclv4_chdr_flags, v4_chdr_flags, ENC_BIG_ENDIAN);
2201 offset += 1;
2203 ctx->tx_peer->can_tls = (flags & TCPCLV4_CONTACT_FLAG_CANTLS);
2206 proto_item_set_len(item_chdr, offset);
2208 if (ctx->tx_peer->chdr_seen) {
2209 if (tcpcl_analyze_sequence) {
2210 if (!tcpcl_frame_loc_equal(ctx->tx_peer->chdr_seen, ctx->cur_loc)) {
2211 expert_add_info(pinfo, item_chdr, &ei_chdr_duplicate);
2215 else {
2216 ctx->tx_peer->chdr_seen = tcpcl_frame_loc_clone(wmem_file_scope(), ctx->cur_loc);
2219 try_negotiate(ctx, pinfo);
2220 // Show negotiation results
2221 if (ctx->convo->contact_negotiated) {
2222 if (ctx->rx_peer->chdr_seen) {
2223 proto_item *item_nego = proto_tree_add_uint(tree_chdr, hf_chdr_related, tvb, 0, 0, ctx->rx_peer->chdr_seen->frame_num);
2224 proto_item_set_generated(item_nego);
2226 if (ctx->tx_peer->version == 4) {
2227 proto_item *item_nego = proto_tree_add_boolean(tree_chdr, hf_tcpclv4_negotiate_use_tls, tvb, 0, 0, ctx->convo->session_use_tls);
2228 proto_item_set_generated(item_nego);
2232 else {
2233 if (ctx->tx_peer->version == 3) {
2234 offset += dissect_v3_msg(tvb, pinfo, tree_tcpcl, ctx);
2236 else if (ctx->tx_peer->version == 4) {
2237 offset += dissect_v4_msg(tvb, pinfo, tree_tcpcl, ctx);
2241 const int item_len = proto_item_get_len(item_tcpcl);
2242 bool is_new_item_tcpcl = (item_len <= 0);
2243 if (is_new_item_tcpcl) {
2244 proto_item_set_len(item_tcpcl, offset);
2245 proto_item_append_text(item_tcpcl, " Version %d", ctx->tx_peer->version);
2247 else {
2248 proto_item_set_len(item_tcpcl, item_len + offset);
2251 if (ctx->xferload) {
2252 col_append_str(pinfo->cinfo, COL_INFO, " [Bundle]");
2254 if (tcpcl_decode_bundle) {
2255 if (bundle_handle) {
2256 call_dissector(
2257 bundle_handle,
2258 ctx->xferload,
2259 pinfo,
2260 tree
2266 return offset;
2269 static int
2270 dissect_tcpcl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
2272 /* Retrieve information from conversation, or add it if it isn't
2273 * there yet */
2274 conversation_t *convo = find_or_create_conversation(pinfo);
2275 tcpcl_conversation_t *tcpcl_convo = (tcpcl_conversation_t *)conversation_get_proto_data(convo, proto_tcpcl);
2276 if (!tcpcl_convo) {
2277 tcpcl_convo = tcpcl_conversation_new();
2278 conversation_add_proto_data(convo, proto_tcpcl, tcpcl_convo);
2279 // Assume the first source (i.e. TCP initiator) is the active node
2280 copy_address_wmem(wmem_file_scope(), &(tcpcl_convo->active->addr), &(pinfo->src));
2281 tcpcl_convo->active->port = pinfo->srcport;
2282 copy_address_wmem(wmem_file_scope(), &(tcpcl_convo->passive->addr), &(pinfo->dst));
2283 tcpcl_convo->passive->port = pinfo->destport;
2286 tcp_dissect_pdus(tvb, pinfo, tree, true, 1, get_message_len, dissect_message, NULL);
2288 const unsigned buflen = tvb_captured_length(tvb);
2289 return buflen;
2292 static bool
2293 dissect_tcpcl_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2295 if (tvb_reported_length(tvb) < minimum_chdr_size) {
2296 return false;
2298 if (tvb_memeql(tvb, 0, magic, sizeof(magic)) != 0) {
2299 return false;
2302 // treat the rest of the connection as TCPCL
2303 conversation_t *convo = find_or_create_conversation(pinfo);
2304 conversation_set_dissector(convo, tcpcl_handle);
2306 dissect_tcpcl(tvb, pinfo, tree, data);
2307 return true;
2310 static int dissect_xferext_transferlen(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_) {
2311 int offset = 0;
2312 tcpcl_dissect_ctx_t *ctx = tcpcl_dissect_ctx_get(tvb, pinfo, offset);
2313 if (!ctx) {
2314 return 0;
2317 uint64_t total_len = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
2318 proto_item *item_len = proto_tree_add_uint64(tree, hf_tcpclv4_xferext_transferlen_total_len, tvb, offset, 8, total_len);
2319 offset += 8;
2320 if (total_len > ctx->rx_peer->transfer_mru) {
2321 expert_add_info(pinfo, item_len, &ei_tcpclv4_xferload_over_xfer_mru);
2324 if (tcpcl_analyze_sequence) {
2325 uint64_t *xfer_id = wmem_map_lookup(ctx->tx_peer->frame_loc_to_transfer, ctx->cur_loc);
2326 if (xfer_id) {
2327 tcpcl_transfer_t *xfer = get_or_create_transfer_t(ctx->tx_peer->transfers, *xfer_id);
2328 xfer->total_length = wmem_new(wmem_file_scope(), uint64_t);
2329 *(xfer->total_length) = total_len;
2333 return offset;
2336 static int dissect_othername_bundleeid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
2337 int offset = 0;
2338 asn1_ctx_t actx;
2339 asn1_ctx_init(&actx, ASN1_ENC_BER, true, pinfo);
2340 offset += dissect_ber_restricted_string(
2341 false, BER_UNI_TAG_IA5String,
2342 &actx, tree, tvb, offset, hf_othername_bundleeid, NULL
2344 return offset;
2347 /// Re-initialize after a configuration change
2348 static void reinit_tcpcl(void) {
2351 void
2352 proto_register_tcpcl(void)
2354 expert_module_t *expert_tcpcl;
2356 proto_tcpcl = proto_register_protocol(
2357 "DTN TCP Convergence Layer Protocol",
2358 "TCPCL",
2359 "tcpcl"
2362 proto_tcpcl_exts = proto_register_protocol_in_name_only(
2363 "TCPCL Extension Subdissectors",
2364 "TCPCL Extension Subdissectors",
2365 "tcpcl_exts",
2366 proto_tcpcl,
2367 FT_PROTOCOL
2370 proto_register_field_array(proto_tcpcl, hf_tcpcl, array_length(hf_tcpcl));
2371 proto_register_subtree_array(ett, array_length(ett));
2372 expert_tcpcl = expert_register_protocol(proto_tcpcl);
2373 expert_register_field_array(expert_tcpcl, ei_tcpcl, array_length(ei_tcpcl));
2375 tcpcl_handle = register_dissector("tcpcl", dissect_tcpcl, proto_tcpcl);
2376 sess_ext_dissectors = register_dissector_table("tcpcl.v4.sess_ext", "TCPCLv4 Session Extension", proto_tcpcl, FT_UINT16, BASE_HEX);
2377 xfer_ext_dissectors = register_dissector_table("tcpcl.v4.xfer_ext", "TCPCLv4 Transfer Extension", proto_tcpcl, FT_UINT16, BASE_HEX);
2379 module_t *module_tcpcl = prefs_register_protocol(proto_tcpcl, reinit_tcpcl);
2380 prefs_register_enum_preference(
2381 module_tcpcl,
2382 "allow_chdr_missing",
2383 "Allow missing Contact Header",
2384 "Whether the TCPCL dissector should use heuristic "
2385 "dissection of messages in the absence of a Contact Header "
2386 "(if the capture misses the start of session).",
2387 &tcpcl_chdr_missing,
2388 chdr_missing_choices,
2389 false
2391 prefs_register_bool_preference(
2392 module_tcpcl,
2393 "analyze_sequence",
2394 "Analyze message sequences",
2395 "Whether the TCPCL dissector should analyze the sequencing of "
2396 "the messages within each session.",
2397 &tcpcl_analyze_sequence
2399 prefs_register_bool_preference(
2400 module_tcpcl,
2401 "desegment_transfer",
2402 "Reassemble the segments of each transfer",
2403 "Whether the TCPCL dissector should combine the sequential segments "
2404 "of a transfer into the full bundle being transferred."
2405 "To use this option, you must also enable "
2406 "\"Allow subdissectors to reassemble TCP streams\" "
2407 "in the TCP protocol settings.",
2408 &tcpcl_desegment_transfer
2410 prefs_register_bool_preference(
2411 module_tcpcl,
2412 "decode_bundle",
2413 "Decode bundle data",
2414 "If enabled, the transfer bundle will be decoded.",
2415 &tcpcl_decode_bundle
2418 reassembly_table_register(
2419 &xfer_reassembly_table,
2420 &xfer_reassembly_table_functions
2425 void
2426 proto_reg_handoff_tcpcl(void)
2428 tls_handle = find_dissector_add_dependency("tls", proto_tcpcl);
2429 bundle_handle = find_dissector("bundle");
2431 dissector_add_uint_with_preference("tcp.port", BUNDLE_PORT, tcpcl_handle);
2432 heur_dissector_add("tcp", dissect_tcpcl_heur, "TCPCL over TCP", "tcpcl_tcp", proto_tcpcl, HEURISTIC_ENABLE);
2434 /* Packaged extensions */
2436 dissector_handle_t dis_h = create_dissector_handle_with_name_and_description(dissect_xferext_transferlen, proto_tcpcl_exts, NULL, "Transfer Length");
2437 dissector_add_uint("tcpcl.v4.xfer_ext", TCPCLV4_XFEREXT_TRANSFER_LEN, dis_h);
2440 register_ber_oid_dissector("1.3.6.1.5.5.7.3.35", NULL, proto_tcpcl_exts, "id-kp-bundleSecurity");
2441 register_ber_oid_dissector("1.3.6.1.5.5.7.8.11", dissect_othername_bundleeid, proto_tcpcl_exts, "id-on-bundleEID");
2443 reinit_tcpcl();
2447 * Editor modelines - https://www.wireshark.org/tools/modelines.html
2449 * Local variables:
2450 * c-basic-offset: 4
2451 * tab-width: 8
2452 * indent-tabs-mode: nil
2453 * End:
2455 * vi: set shiftwidth=4 tabstop=8 expandtab:
2456 * :indentSize=4:tabSize=8:noTabs=true: