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.
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
42 #include <epan/packet.h>
43 #include <epan/reassemble.h>
44 #include <epan/expert.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
{
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
},
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
;
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"},
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"},
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"},
132 static const value_string v4_sess_term_reason_vals
[]={
134 {0x01, "Idle timeout"},
135 {0x02, "Version mismatch"},
137 {0x04, "Contact Failure"},
138 {0x05, "Resource Exhaustion"},
142 static const value_string v4_xfer_refuse_reason_vals
[]={
145 {0x02, "No Resources"},
146 {0x03, "Retransmit"},
147 {0x04, "Not Acceptable"},
148 {0x05, "Extension Failure"},
152 static const value_string v4_msg_reject_reason_vals
[]={
154 {0x01, "Message Type Unknown"},
155 {0x02, "Message Unsupported"},
156 {0x03, "Message Unexpected"},
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
}},
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
}},
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
}},
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
}},
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
}},
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
}},
438 {"Transfer fragments", "tcpcl.xfer.fragments",
439 FT_NONE
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
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
,
482 static int *const v3_data_procflags
[] = {
483 &hf_tcpclv3_data_procflags_start
,
484 &hf_tcpclv3_data_procflags_end
,
487 static int *const v4_chdr_flags
[] = {
488 &hf_tcpclv4_chdr_flags_cantls
,
491 static int *const v4_sess_term_flags
[] = {
492 &hf_tcpclv4_sess_term_flags_reply
,
495 static int *const v4_xfer_flags
[] = {
496 &hf_tcpclv4_xfer_flags_start
,
497 &hf_tcpclv4_xfer_flags_end
,
500 static int *const v4_sessext_flags
[] = {
501 &hf_tcpclv4_sessext_flags_crit
,
504 static int *const v4_xferext_flags
[] = {
505 &hf_tcpclv4_xferext_flags_crit
,
509 /* Tree Node Variables */
510 static int ett_proto_tcpcl
;
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
[] = {
532 &ett_tcpclv3_chdr_flags
,
534 &ett_tcpclv3_data_procflags
,
535 &ett_tcpclv3_shutdown_flags
,
536 &ett_tcpclv4_chdr_flags
,
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
,
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*/
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
,
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
652 for(GSList
*srcit
= pinfo
->data_src
; srcit
!= NULL
; srcit
= g_slist_next(srcit
)) {
654 struct data_source
*src
= srcit
->data
;
655 if (get_data_source_tvb(src
)->real_data
== tvb
->real_data
) {
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
);
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
);
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
) {
689 else if (aloc
->frame_num
> bloc
->frame_num
) {
693 if (aloc
->raw_offset
< bloc
->raw_offset
) {
696 else if (aloc
->raw_offset
> bloc
->raw_offset
) {
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
;
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
;
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)
733 /// Copy of message flags
735 /// Total transfer length including this segment
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
;
750 obj
->related_start
= NULL
;
751 obj
->related_ack
= NULL
;
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
),
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)
774 /// Copy of message flags
776 /// Total acknowledged length including this ack
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
;
791 obj
->related_start
= NULL
;
792 obj
->related_seg
= NULL
;
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
),
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
;
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
);
821 uint64_t *key
= wmem_new(wmem_file_scope(), uint64_t);
823 xfer
= tcpcl_transfer_new();
824 wmem_map_insert(table
, key
, 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
);
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
);
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);
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();
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
);
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
)
869 ctx
->tx_peer
= ctx
->convo
->active
;
870 ctx
->rx_peer
= ctx
->convo
->passive
;
873 ctx
->tx_peer
= ctx
->convo
->passive
;
874 ctx
->rx_peer
= ctx
->convo
->active
;
878 !(ctx
->tx_peer
->chdr_missing
)
880 !(ctx
->tx_peer
->chdr_seen
)
881 || tcpcl_frame_loc_equal(ctx
->tx_peer
->chdr_seen
, ctx
->cur_loc
)
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;
927 // key type for addresses_ports_reassembly_table_functions
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
;
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
;
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
);
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
);
964 static void fragment_key_free_temporary(void *ptr
) {
965 tcpcl_fragment_key_t
*obj
= (tcpcl_fragment_key_t
*)ptr
;
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
;
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
= {
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
,
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
;
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
);
1011 tcpcl_seg_meta_free(seg_meta
);
1012 seg_meta
= wmem_list_frame_data(frm
);
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
);
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
);
1034 if (!(flags
& flag_start
)) {
1035 expert_add_info(pinfo
, item_flags
, &ei_tcpclv4_xfer_seg_missing_start
);
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
);
1048 if (!(flags
& flag_end
)) {
1049 expert_add_info(pinfo
, item_flags
, &ei_tcpclv4_xfer_seg_missing_end
);
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
);
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
);
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
);
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
,
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
);
1110 tcpcl_ack_meta_free(ack_meta
);
1111 ack_meta
= wmem_list_frame_data(frm
);
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
);
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
);
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
);
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
);
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
;
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
;
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
);
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
) {
1195 if (orig
> INT_MAX
) {
1197 if (pinfo
&& item
) {
1198 expert_add_info(pinfo
, item
, &ei_length_clamped
);
1202 clamped
= (int) orig
;
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
;
1214 uint8_t conv_hdr
= tvb_get_uint8(tvb
, offset
);
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) {
1225 const int len_clamp
= get_clamped_length(len
, NULL
, NULL
);
1226 offset
+= bytecount
+ len_clamp
;
1229 case TCPCLV3_ACK_SEGMENT
:
1230 /* get length from sdnv */
1231 bytecount
= tvb_get_sdnv(tvb
, offset
, &len
);
1232 if (bytecount
== 0) {
1235 offset
+= bytecount
;
1238 case TCPCLV3_KEEP_ALIVE
:
1239 case TCPCLV3_REFUSE_BUNDLE
:
1242 case TCPCLV3_SHUTDOWN
:
1243 if (conv_hdr
& TCPCLV3_SHUTDOWN_REASON
) {
1246 if (conv_hdr
& TCPCLV3_SHUTDOWN_DELAY
) {
1251 case TCPCLV3_LENGTH
:
1252 /* get length from sdnv */
1253 bytecount
= tvb_get_sdnv(tvb
, offset
, &len
);
1254 if (bytecount
== 0) {
1257 offset
+= bytecount
;
1265 return offset
- orig_offset
;
1269 dissect_v3_msg(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
1270 tcpcl_dissect_ctx_t
*ctx
)
1273 const char *msgtype_name
;
1274 uint8_t refuse_bundle_hdr
;
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(
1299 offset
, hf_tcpclv3_data_procflags
,
1300 ett_tcpclv3_data_procflags
, v3_data_procflags
,
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
);
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
);
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
) {
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
,
1347 !(conv_hdr
& TCPCLV3_DATA_END_FLAG
)
1349 ctx
->xferload
= process_reassembled_data(
1351 "Reassembled Transfer",
1355 proto_tree_get_parent_tree(tree
)
1358 offset
+= data_len_clamp
;
1362 case TCPCLV3_ACK_SEGMENT
: {
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
);
1370 offset
+= sdnv_length
;
1373 // implied transfer ID
1374 xfer_id
= wmem_map_lookup(ctx
->rx_peer
->frame_loc_to_transfer
, ctx
->cur_loc
);
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
);
1390 case TCPCLV3_KEEP_ALIVE
:
1391 /*No valid flags in Keep Alive*/
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
);
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
);
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
);
1420 case TCPCLV3_REFUSE_BUNDLE
:
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
);
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
);
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
);
1447 expert_add_info(pinfo
, proto_tree_get_parent(conv_tree
), &ei_tcpclv3_invalid_msg_type
);
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
);
1460 case TCPCLV4_MSGTYPE_SESS_INIT
: {
1461 const int buflen
= tvb_reported_length(tvb
);
1462 offset
+= 2 + 8 + 8;
1463 if (buflen
< offset
+ 2) {
1466 uint16_t nodeid_len
= tvb_get_uint16(tvb
, offset
, ENC_BIG_ENDIAN
);
1468 offset
+= nodeid_len
;
1469 if (buflen
< offset
+ 4) {
1472 uint32_t extlist_len
= tvb_get_uint32(tvb
, offset
, ENC_BIG_ENDIAN
);
1474 offset
+= extlist_len
;
1477 case TCPCLV4_MSGTYPE_SESS_TERM
: {
1481 case TCPCLV4_MSGTYPE_XFER_SEGMENT
: {
1482 const int buflen
= tvb_reported_length(tvb
);
1483 if (buflen
< offset
+ 1) {
1486 uint8_t flags
= tvb_get_uint8(tvb
, offset
);
1489 if (flags
& TCPCLV4_TRANSFER_FLAG_START
) {
1490 if (buflen
< offset
+ 4) {
1493 uint32_t extlist_len
= tvb_get_uint32(tvb
, offset
, ENC_BIG_ENDIAN
);
1495 offset
+= extlist_len
;
1497 if (buflen
< offset
+ 8) {
1500 uint64_t data_len
= tvb_get_uint64(tvb
, offset
, ENC_BIG_ENDIAN
);
1502 const int data_len_clamp
= get_clamped_length(data_len
, NULL
, NULL
);
1503 offset
+= data_len_clamp
;
1506 case TCPCLV4_MSGTYPE_XFER_ACK
: {
1507 offset
+= 1 + 8 + 8;
1510 case TCPCLV4_MSGTYPE_XFER_REFUSE
: {
1514 case TCPCLV4_MSGTYPE_KEEPALIVE
: {
1517 case TCPCLV4_MSGTYPE_MSG_REJECT
: {
1525 return offset
- init_offset
;
1529 dissect_v4_msg(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
1530 tcpcl_dissect_ctx_t
*ctx _U_
) {
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
1610 sublen
= call_dissector_only(subdis
, extitem_tvb
, pinfo
, tree_extdata
, NULL
);
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
;
1621 proto_item_append_text(item_ext
, ": %s", subname
);
1624 proto_item_append_text(item_ext
, ": Type 0x%04" PRIx16
, extitem_type
);
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
);
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
;
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
1737 sublen
= call_dissector_only(subdis
, extitem_tvb
, pinfo
, tree_extdata
, NULL
);
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
;
1748 proto_item_append_text(item_ext
, ": %s", subname
);
1751 proto_item_append_text(item_ext
, ": Type 0x%04" PRIx16
, extitem_type
);
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
);
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
);
1779 wmem_strbuf_append(suffix_text
, ", Flags: ");
1781 if (flags
& TCPCLV4_TRANSFER_FLAG_START
) {
1782 wmem_strbuf_append(suffix_text
, "START");
1785 if (flags
& TCPCLV4_TRANSFER_FLAG_END
) {
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
,
1804 !(flags
& TCPCLV4_TRANSFER_FLAG_END
)
1806 ctx
->xferload
= process_reassembled_data(
1807 tvb
, data_offset
, pinfo
,
1808 "Reassembled Transfer",
1812 proto_tree_get_parent_tree(tree
)
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
);
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
);
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
);
1831 wmem_strbuf_append_printf(suffix_text
, ", Xfer ID: %" PRIi64
, xfer_id
);
1834 wmem_strbuf_append(suffix_text
, ", Flags: ");
1836 if (flags
& TCPCLV4_TRANSFER_FLAG_START
) {
1837 wmem_strbuf_append(suffix_text
, "START");
1840 if (flags
& TCPCLV4_TRANSFER_FLAG_END
) {
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
);
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
);
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
);
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
);
1871 case TCPCLV4_MSGTYPE_KEEPALIVE
: {
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
);
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
);
1886 expert_add_info(pinfo
, item_msg
, &ei_tcpclv4_invalid_msg_type
);
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
);
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
);
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
);
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
1947 // similar heuristics to is_sslv3_or_tls() from packet-tls.c
1948 if (tvb_captured_length(tvb
) < 5) {
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
);
1956 // These overlap with TCPCLV3_DATA_SEGMENT but have invalid flags
1957 // They are valid but unallocated v4 message type codes
1959 case SSL_ID_HANDSHAKE
:
1960 case SSL_ID_APP_DATA
:
1961 case SSL_ID_HEARTBEAT
:
1966 if ((recvers
& 0xFF00) != 0x0300) {
1969 if (reclen
== 0 || reclen
>= TLS_MAX_RECORD_LENGTH
+ 2048) {
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
);
1986 set_chdr_missing(ctx
->tx_peer
, 3);
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
);
1995 set_chdr_missing(ctx
->tx_peer
, 4);
2000 static const chdr_missing_check chdr_missing_v3first
[] = {
2006 static const chdr_missing_check chdr_missing_v3only
[] = {
2010 static const chdr_missing_check chdr_missing_v4first
[] = {
2016 static const chdr_missing_check chdr_missing_v4only
[] = {
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
);
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
;
2037 case CHDRMSN_V3ONLY
:
2038 checks
= chdr_missing_v3only
;
2040 case CHDRMSN_V4FIRST
:
2041 checks
= chdr_missing_v4first
;
2043 case CHDRMSN_V4ONLY
:
2044 checks
= chdr_missing_v4only
;
2048 for (const chdr_missing_check
*chk
= checks
; *chk
; ++chk
) {
2049 unsigned sublen
= (**chk
)(pinfo
, tvb
, offset
, ctx
);
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
2067 offset
+= sizeof(magic
);
2069 uint8_t version
= tvb_get_uint8(tvb
, offset
);
2072 offset
+= 3; // flags + keepalive
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
2086 if (ctx
->tx_peer
->version
== 3) {
2087 unsigned sublen
= get_v3_msg_len(pinfo
, tvb
, offset
, ctx
);
2093 else if (ctx
->tx_peer
->version
== 4) {
2094 unsigned sublen
= get_v4_msg_len(pinfo
, tvb
, offset
, ctx
);
2104 const int needlen
= offset
- init_offset
;
2108 static int dissect_message(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
) {
2110 tcpcl_dissect_ctx_t
*ctx
= tcpcl_dissect_ctx_get(tvb
, pinfo
, offset
);
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
);
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
);
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
);
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
);
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
);
2175 proto_tree_add_item(tree_chdr
, hf_tcpclv3_chdr_keep_alive
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
2179 * New format Contact header has length field followed by EID.
2181 uint64_t eid_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
);
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
);
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
);
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
);
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
);
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
) {
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
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
);
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
);
2293 dissect_tcpcl_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
2295 if (tvb_reported_length(tvb
) < minimum_chdr_size
) {
2298 if (tvb_memeql(tvb
, 0, magic
, sizeof(magic
)) != 0) {
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
);
2310 static int dissect_xferext_transferlen(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
, void *data _U_
) {
2312 tcpcl_dissect_ctx_t
*ctx
= tcpcl_dissect_ctx_get(tvb
, pinfo
, offset
);
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
);
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
);
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
;
2336 static int dissect_othername_bundleeid(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
) {
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
2347 /// Re-initialize after a configuration change
2348 static void reinit_tcpcl(void) {
2352 proto_register_tcpcl(void)
2354 expert_module_t
*expert_tcpcl
;
2356 proto_tcpcl
= proto_register_protocol(
2357 "DTN TCP Convergence Layer Protocol",
2362 proto_tcpcl_exts
= proto_register_protocol_in_name_only(
2363 "TCPCL Extension Subdissectors",
2364 "TCPCL Extension Subdissectors",
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(
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
,
2391 prefs_register_bool_preference(
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(
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(
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
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");
2447 * Editor modelines - https://www.wireshark.org/tools/modelines.html
2452 * indent-tabs-mode: nil
2455 * vi: set shiftwidth=4 tabstop=8 expandtab:
2456 * :indentSize=4:tabSize=8:noTabs=true: