Coverage Report

Created: 2025-02-15 06:25

/src/wireshark/epan/dissectors/packet-tcpcl.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-tcpcl.c
2
 * References:
3
 *     RFC 7242: https://tools.ietf.org/html/rfc7242
4
 *     RFC 9174: https://www.rfc-editor.org/rfc/rfc9174.html
5
 *
6
 * TCPCLv4 portions copyright 2019-2021, Brian Sipos <brian.sipos@gmail.com>
7
 * Copyright 2006-2007 The MITRE Corporation.
8
 * All Rights Reserved.
9
 * Approved for Public Release; Distribution Unlimited.
10
 * Tracking Number 07-0090.
11
 *
12
 * The US Government will not be charged any license fee and/or royalties
13
 * related to this software. Neither name of The MITRE Corporation; nor the
14
 * names of its contributors may be used to endorse or promote products
15
 * derived from this software without specific prior written permission.
16
 *
17
 * Wireshark - Network traffic analyzer
18
 * By Gerald Combs <gerald@wireshark.org>
19
 * Copyright 1998 Gerald Combs
20
 *
21
 * SPDX-License-Identifier: GPL-2.0-or-later
22
 */
23
24
/*
25
 *    Modifications were made to this file under designation MFS-33289-1 and
26
 *    are Copyright 2015 United States Government as represented by NASA
27
 *       Marshall Space Flight Center. All Rights Reserved.
28
 *
29
 *    Released under the GNU GPL with NASA legal approval granted 2016-06-10.
30
 *
31
 *    The subject software is provided "AS IS" WITHOUT ANY WARRANTY of any kind,
32
 *    either expressed, implied or statutory and this agreement does not,
33
 *    in any manner, constitute an endorsement by government agency of any
34
 *    results, designs or products resulting from use of the subject software.
35
 *    See the Agreement for the specific language governing permissions and
36
 *    limitations.
37
 */
38
39
#include "config.h"
40
41
#include <inttypes.h>
42
#include <epan/packet.h>
43
#include <epan/reassemble.h>
44
#include <epan/expert.h>
45
#include <epan/tfs.h>
46
#include <epan/tvbuff-int.h>
47
#include <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"
53
54
void proto_register_tcpcl(void);
55
void proto_reg_handoff_tcpcl(void);
56
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;
61
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,
69
};
70
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},
78
};
79
80
static int proto_tcpcl;
81
static int proto_tcpcl_exts;
82
/// Protocol column name
83
static const char *const proto_name_tcpcl = "TCPCL";
84
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;
89
90
/* For Reassembling TCP Convergence Layer segments */
91
static reassembly_table xfer_reassembly_table;
92
93
/// Dissector handles
94
static dissector_handle_t tcpcl_handle;
95
static dissector_handle_t tls_handle;
96
static dissector_handle_t bundle_handle;
97
98
/// Extension sub-dissectors
99
static dissector_table_t sess_ext_dissectors;
100
static dissector_table_t xfer_ext_dissectors;
101
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}
110
};
111
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}
119
};
120
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},
130
};
131
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},
140
};
141
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},
150
};
151
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},
158
};
159
160
static int hf_chdr_tree;
161
static int hf_chdr_magic;
162
static int hf_chdr_version;
163
static int hf_chdr_related;
164
165
/* TCP Convergence Header Variables */
166
static int hf_tcpclv3_mhdr;
167
static int hf_tcpclv3_pkt_type;
168
169
/* Refuse-Bundle reason code */
170
static int hf_tcpclv3_refuse_reason_code;
171
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;
179
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;
187
188
/* TCP Convergence Ack Variables */
189
static int hf_tcpclv3_ack_length;
190
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;
197
198
static int hf_tcpclv4_chdr_flags;
199
static int hf_tcpclv4_chdr_flags_cantls;
200
static int hf_tcpclv4_negotiate_use_tls;
201
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;
212
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;
217
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;
224
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;
231
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;
254
255
static int hf_tcpclv4_xferext_transferlen_total_len;
256
257
static int hf_othername_bundleeid;
258
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;
271
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}},
277
278
    {&hf_tcpclv3_mhdr,
279
     {"TCPCLv3 Message", "tcpcl.mhdr",
280
      FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}
281
    },
282
    {&hf_tcpclv3_pkt_type,
283
     {"Message Type", "tcpcl.pkt_type",
284
      FT_UINT8, BASE_DEC, VALS(v3_message_type_vals), 0xF0, NULL, HFILL}
285
    },
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}
289
    },
290
    {&hf_tcpclv3_data_procflags,
291
     {"Data Flags", "tcpcl.data.proc.flag",
292
      FT_UINT8, BASE_HEX, NULL, TCPCLV3_DATA_FLAGS, NULL, HFILL}
293
    },
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}
297
    },
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}
301
    },
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}
306
    },
307
    {&hf_tcpclv3_data_segment_data,
308
     {"Segment Data", "tcpcl.data",
309
      FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}
310
    },
311
    {&hf_tcpclv3_shutdown_flags,
312
     {"TCP Convergence Shutdown Flags", "tcpcl.shutdown.flags",
313
      FT_UINT8, BASE_HEX, NULL, TCPCLV3_SHUTDOWN_FLAGS, NULL, HFILL}
314
    },
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}
318
    },
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}
322
    },
323
    {&hf_tcpclv3_shutdown_reason,
324
     {"Shutdown Reason Code", "tcpcl.shutdown.reason",
325
      FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}
326
    },
327
    {&hf_tcpclv3_shutdown_delay,
328
     {"Shutdown Reconnection Delay", "tcpcl.shutdown.delay",
329
      FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
330
    },
331
    {&hf_tcpclv3_ack_length,
332
     {"Ack Length", "tcpcl.ack.length",
333
      FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL}
334
    },
335
    {&hf_tcpclv3_chdr_flags,
336
     {"Flags", "tcpcl.contact_hdr.flags",
337
      FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
338
    },
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}
342
    },
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}
346
    },
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}
350
    },
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}
354
    },
355
    {&hf_tcpclv3_chdr_local_eid,
356
     {"Local EID", "tcpcl.contact_hdr.local_eid",
357
      FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}
358
    },
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}
362
    },
363
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}},
368
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}},
371
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}},
379
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}},
387
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}},
403
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}},
431
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}},
436
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 } },
472
473
};
474
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
480
};
481
482
static int *const v3_data_procflags[] = {
483
    &hf_tcpclv3_data_procflags_start,
484
    &hf_tcpclv3_data_procflags_end,
485
    NULL
486
};
487
static int *const v4_chdr_flags[] = {
488
    &hf_tcpclv4_chdr_flags_cantls,
489
    NULL
490
};
491
static int *const v4_sess_term_flags[] = {
492
    &hf_tcpclv4_sess_term_flags_reply,
493
    NULL
494
};
495
static int *const v4_xfer_flags[] = {
496
    &hf_tcpclv4_xfer_flags_start,
497
    &hf_tcpclv4_xfer_flags_end,
498
    NULL
499
};
500
static int *const v4_sessext_flags[] = {
501
    &hf_tcpclv4_sessext_flags_crit,
502
    NULL
503
};
504
static int *const v4_xferext_flags[] = {
505
    &hf_tcpclv4_xferext_flags_crit,
506
    NULL
507
};
508
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;
528
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,
548
};
549
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;
556
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;
562
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;
583
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}},
591
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 }},
597
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}},
618
};
619
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"
641
};
642
643
1.87k
static unsigned tvb_get_sdnv(tvbuff_t *tvb, unsigned offset, uint64_t *value) {
644
1.87k
    return tvb_get_varint(tvb, offset, FT_VARINT_MAX_LEN, value, ENC_VARINT_SDNV);
645
1.87k
}
646
647
8.09k
static void tcpcl_frame_loc_init(tcpcl_frame_loc_t *loc, const packet_info *pinfo, tvbuff_t *tvb, const int offset) {
648
8.09k
    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
8.09k
    loc->src_ix = -1;
652
18.5k
    for(GSList *srcit = pinfo->data_src; srcit != NULL; srcit = g_slist_next(srcit)) {
653
10.5k
        ++(loc->src_ix);
654
10.5k
        struct data_source *src = srcit->data;
655
10.5k
        if (get_data_source_tvb(src)->real_data == tvb->real_data) {
656
78
            break;
657
78
        }
658
10.5k
    }
659
8.09k
    loc->raw_offset = tvb_raw_offset(tvb) + offset;
660
8.09k
}
661
662
/** Construct a new object on the file allocator.
663
 */
664
8.09k
static tcpcl_frame_loc_t * tcpcl_frame_loc_new(wmem_allocator_t *alloc, const packet_info *pinfo, tvbuff_t *tvb, const int offset) {
665
8.09k
    tcpcl_frame_loc_t *obj = wmem_new(alloc, tcpcl_frame_loc_t);
666
8.09k
    tcpcl_frame_loc_init(obj, pinfo, tvb, offset);
667
8.09k
    return obj;
668
8.09k
}
669
670
/** Construct a new object on the file allocator.
671
 */
672
1.42k
static tcpcl_frame_loc_t * tcpcl_frame_loc_clone(wmem_allocator_t *alloc, const tcpcl_frame_loc_t *loc) {
673
1.42k
    tcpcl_frame_loc_t *obj = wmem_new(alloc, tcpcl_frame_loc_t);
674
1.42k
    *obj = *loc;
675
1.42k
    return obj;
676
1.42k
}
677
678
#define tcpcl_frame_loc_free wmem_free
679
680
/** Function to match the GCompareDataFunc signature.
681
 */
682
2.81k
static int tcpcl_frame_loc_compare(const void *a, const void *b, void *user_data _U_) {
683
2.81k
    const tcpcl_frame_loc_t *aloc = a;
684
2.81k
    const tcpcl_frame_loc_t *bloc = b;
685
686
2.81k
    if (aloc->frame_num < bloc->frame_num) {
687
432
        return -1;
688
432
    }
689
2.37k
    else if (aloc->frame_num > bloc->frame_num) {
690
0
        return 1;
691
0
    }
692
693
2.37k
    if (aloc->raw_offset < bloc->raw_offset) {
694
930
        return -1;
695
930
    }
696
1.44k
    else if (aloc->raw_offset > bloc->raw_offset) {
697
0
        return 1;
698
0
    }
699
1.44k
    return 0;
700
2.37k
}
701
702
/** Function to match the GCompareFunc signature.
703
 */
704
1.92k
static gboolean tcpcl_frame_loc_equal(const void *a, const void *b) {
705
1.92k
    const tcpcl_frame_loc_t *aobj = a;
706
1.92k
    const tcpcl_frame_loc_t *bobj = b;
707
1.92k
    return (
708
1.92k
        (aobj->frame_num == bobj->frame_num)
709
1.92k
        && (aobj->raw_offset == bobj->raw_offset)
710
1.92k
    );
711
1.92k
}
712
713
/** Function to match the GHashFunc signature.
714
 */
715
5.54k
static unsigned tcpcl_frame_loc_hash(const void *key) {
716
5.54k
    const tcpcl_frame_loc_t *obj = key;
717
5.54k
    return (
718
5.54k
        g_int_hash(&(obj->frame_num))
719
5.54k
        ^ g_int_hash(&(obj->raw_offset))
720
5.54k
    );
721
5.54k
}
722
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;
727
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;
737
738
    /// Potential related start segment
739
    tcpcl_seg_meta_t *related_start;
740
    /// Potential related XFER_ACK
741
    tcpcl_ack_meta_t *related_ack;
742
};
743
744
319
static tcpcl_seg_meta_t * tcpcl_seg_meta_new(const packet_info *pinfo, const tcpcl_frame_loc_t *loc) {
745
319
    tcpcl_seg_meta_t *obj = wmem_new(wmem_file_scope(), tcpcl_seg_meta_t);
746
319
    obj->frame_loc = *loc;
747
319
    obj->frame_time = pinfo->abs_ts;
748
319
    obj->flags = 0;
749
319
    obj->seen_len = 0;
750
319
    obj->related_start = NULL;
751
319
    obj->related_ack = NULL;
752
319
    return obj;
753
319
}
754
755
0
static void tcpcl_seg_meta_free(tcpcl_seg_meta_t *obj) {
756
0
    wmem_free(wmem_file_scope(), obj);
757
0
}
758
759
/** Function to match the GCompareFunc signature.
760
 */
761
1.56k
static int tcpcl_seg_meta_compare_loc(const void *a, const void *b) {
762
1.56k
    return tcpcl_frame_loc_compare(
763
1.56k
        &(((tcpcl_seg_meta_t *)a)->frame_loc),
764
1.56k
        &(((tcpcl_seg_meta_t *)b)->frame_loc),
765
1.56k
        NULL
766
1.56k
    );
767
1.56k
}
768
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;
778
779
    /// Potential related start segment
780
    tcpcl_seg_meta_t *related_start;
781
    /// Potential related XFER_SEGMENT
782
    tcpcl_seg_meta_t *related_seg;
783
};
784
785
1.13k
static tcpcl_ack_meta_t * tcpcl_ack_meta_new(const packet_info *pinfo, const tcpcl_frame_loc_t *loc) {
786
1.13k
    tcpcl_ack_meta_t *obj = wmem_new(wmem_file_scope(), tcpcl_ack_meta_t);
787
1.13k
    obj->frame_loc = *loc;
788
1.13k
    obj->frame_time = pinfo->abs_ts;
789
1.13k
    obj->flags = 0;
790
1.13k
    obj->seen_len = 0;
791
1.13k
    obj->related_start = NULL;
792
1.13k
    obj->related_seg = NULL;
793
1.13k
    return obj;
794
1.13k
}
795
796
1
static void tcpcl_ack_meta_free(tcpcl_ack_meta_t *obj) {
797
1
    wmem_free(wmem_file_scope(), obj);
798
1
}
799
800
/** Function to match the GCompareFunc signature.
801
 */
802
1.24k
static int tcpcl_ack_meta_compare_loc(const void *a, const void *b) {
803
1.24k
    return tcpcl_frame_loc_compare(
804
1.24k
        &(((tcpcl_seg_meta_t *)a)->frame_loc),
805
1.24k
        &(((tcpcl_seg_meta_t *)b)->frame_loc),
806
1.24k
        NULL
807
1.24k
    );
808
1.24k
}
809
810
1.28k
static tcpcl_transfer_t * tcpcl_transfer_new(void) {
811
1.28k
    tcpcl_transfer_t *obj = wmem_new(wmem_file_scope(), tcpcl_transfer_t);
812
1.28k
    obj->seg_list = wmem_list_new(wmem_file_scope());
813
1.28k
    obj->ack_list = wmem_list_new(wmem_file_scope());
814
1.28k
    obj->total_length = NULL;
815
1.28k
    return obj;
816
1.28k
}
817
818
1.58k
static tcpcl_transfer_t * get_or_create_transfer_t(wmem_map_t *table, const uint64_t xfer_id) {
819
1.58k
    tcpcl_transfer_t *xfer = wmem_map_lookup(table, &xfer_id);
820
1.58k
    if (!xfer) {
821
1.28k
        uint64_t *key = wmem_new(wmem_file_scope(), uint64_t);
822
1.28k
        *key = xfer_id;
823
1.28k
        xfer = tcpcl_transfer_new();
824
1.28k
        wmem_map_insert(table, key, xfer);
825
1.28k
    }
826
1.58k
    return xfer;
827
1.58k
}
828
829
134
static tcpcl_peer_t * tcpcl_peer_new(void) {
830
134
    tcpcl_peer_t *obj = wmem_new0(wmem_file_scope(), tcpcl_peer_t);
831
134
    clear_address(&(obj->addr));
832
134
    obj->frame_loc_to_transfer = wmem_map_new(wmem_file_scope(), tcpcl_frame_loc_hash, tcpcl_frame_loc_equal);
833
134
    obj->transfers = wmem_map_new(wmem_file_scope(), g_int64_hash, g_int64_equal);
834
134
    return obj;
835
134
}
836
837
1.42k
static void tcpcl_peer_associate_transfer(tcpcl_peer_t *peer, const tcpcl_frame_loc_t *loc, const uint64_t xfer_id) {
838
1.42k
    void * *xfer = wmem_map_lookup(peer->frame_loc_to_transfer, loc);
839
1.42k
    if (!xfer) {
840
1.42k
        tcpcl_frame_loc_t *key = tcpcl_frame_loc_clone(wmem_file_scope(), loc);
841
1.42k
        uint64_t *val = wmem_new(wmem_file_scope(), uint64_t);
842
1.42k
        *val = xfer_id;
843
1.42k
        wmem_map_insert(peer->frame_loc_to_transfer, key, val);
844
1.42k
    }
845
1.42k
}
846
847
67
static tcpcl_conversation_t * tcpcl_conversation_new(void) {
848
67
    tcpcl_conversation_t *obj = wmem_new0(wmem_file_scope(), tcpcl_conversation_t);
849
67
    obj->active = tcpcl_peer_new();
850
67
    obj->passive = tcpcl_peer_new();
851
67
    return obj;
852
67
}
853
854
8.09k
tcpcl_dissect_ctx_t * tcpcl_dissect_ctx_get(tvbuff_t *tvb, packet_info *pinfo, const int offset) {
855
8.09k
    conversation_t *convo = find_or_create_conversation(pinfo);
856
8.09k
    tcpcl_conversation_t *tcpcl_convo = (tcpcl_conversation_t *)conversation_get_proto_data(convo, proto_tcpcl);
857
8.09k
    if (!tcpcl_convo) {
858
0
        return NULL;
859
0
    }
860
8.09k
    tcpcl_dissect_ctx_t *ctx = wmem_new0(wmem_packet_scope(), tcpcl_dissect_ctx_t);
861
8.09k
    ctx->convo = tcpcl_convo;
862
8.09k
    ctx->cur_loc = tcpcl_frame_loc_new(wmem_packet_scope(), pinfo, tvb, offset);
863
864
8.09k
    const bool src_is_active = (
865
8.09k
        addresses_equal(&(ctx->convo->active->addr), &(pinfo->src))
866
8.09k
        && (ctx->convo->active->port == pinfo->srcport)
867
8.09k
    );
868
8.09k
    if (src_is_active) {
869
8.09k
        ctx->tx_peer = ctx->convo->active;
870
8.09k
        ctx->rx_peer = ctx->convo->passive;
871
8.09k
    }
872
0
    else {
873
0
        ctx->tx_peer = ctx->convo->passive;
874
0
        ctx->rx_peer = ctx->convo->active;
875
0
    }
876
877
8.09k
    ctx->is_contact = (
878
8.09k
        !(ctx->tx_peer->chdr_missing)
879
8.09k
        && (
880
136
            !(ctx->tx_peer->chdr_seen)
881
136
            || tcpcl_frame_loc_equal(ctx->tx_peer->chdr_seen, ctx->cur_loc)
882
136
        )
883
8.09k
    );
884
885
8.09k
    return ctx;
886
8.09k
}
887
888
61
static void set_chdr_missing(tcpcl_peer_t *peer, uint8_t version) {
889
61
    peer->chdr_missing = true;
890
61
    peer->version = version;
891
    // assumed parameters
892
61
    peer->segment_mru = UINT64_MAX;
893
61
    peer->transfer_mru = UINT64_MAX;
894
61
}
895
896
897
65
static void try_negotiate(tcpcl_dissect_ctx_t *ctx, packet_info *pinfo) {
898
65
    if (!(ctx->convo->contact_negotiated)
899
65
        && (ctx->convo->active->chdr_seen)
900
65
        && (ctx->convo->passive->chdr_seen)) {
901
0
        ctx->convo->session_use_tls = (
902
0
            ctx->convo->active->can_tls & ctx->convo->passive->can_tls
903
0
        );
904
0
        ctx->convo->contact_negotiated = true;
905
906
0
        if (ctx->convo->session_use_tls
907
0
            && (!(ctx->convo->session_tls_start))) {
908
0
            col_append_str(pinfo->cinfo, COL_INFO, " [STARTTLS]");
909
0
            ctx->convo->session_tls_start = tcpcl_frame_loc_clone(wmem_file_scope(), ctx->cur_loc);
910
0
            ssl_starttls_ack(tls_handle, pinfo, tcpcl_handle);
911
0
        }
912
0
    }
913
914
65
    if (!(ctx->convo->sess_negotiated)
915
65
        && (ctx->convo->active->sess_init_seen)
916
65
        && (ctx->convo->passive->sess_init_seen)) {
917
0
        ctx->convo->sess_keepalive = MIN(
918
0
            ctx->convo->active->keepalive,
919
0
            ctx->convo->passive->keepalive
920
0
        );
921
0
        ctx->convo->sess_negotiated = true;
922
923
0
    }
924
65
}
925
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;
932
933
453
static unsigned fragment_key_hash(const void *ptr) {
934
453
    const tcpcl_fragment_key_t *obj = (const tcpcl_fragment_key_t *)ptr;
935
453
    return (
936
453
        addresses_ports_reassembly_table_functions.hash_func(obj->addr_port)
937
453
        ^ g_int64_hash(&(obj->xfer_id))
938
453
    );
939
453
}
940
941
1.02k
static gboolean fragment_key_equal(const void *ptrA, const void *ptrB) {
942
1.02k
    const tcpcl_fragment_key_t *objA = (const tcpcl_fragment_key_t *)ptrA;
943
1.02k
    const tcpcl_fragment_key_t *objB = (const tcpcl_fragment_key_t *)ptrB;
944
1.02k
    return (
945
1.02k
        addresses_ports_reassembly_table_functions.equal_func(objA->addr_port, objB->addr_port)
946
1.02k
        && (objA->xfer_id == objB->xfer_id)
947
1.02k
    );
948
1.02k
}
949
950
319
static void *fragment_key_temporary(const packet_info *pinfo, const uint32_t id, const void *data) {
951
319
    tcpcl_fragment_key_t *obj = g_slice_new(tcpcl_fragment_key_t);
952
319
    obj->addr_port = addresses_ports_reassembly_table_functions.temporary_key_func(pinfo, id, NULL);
953
319
    obj->xfer_id = *((const uint64_t *)data);
954
319
    return (void *)obj;
955
319
}
956
957
98
static void *fragment_key_persistent(const packet_info *pinfo, const uint32_t id, const void *data) {
958
98
    tcpcl_fragment_key_t *obj = g_slice_new(tcpcl_fragment_key_t);
959
98
    obj->addr_port = addresses_ports_reassembly_table_functions.persistent_key_func(pinfo, id, NULL);
960
98
    obj->xfer_id = *((const uint64_t *)data);
961
98
    return (void *)obj;
962
98
}
963
964
319
static void fragment_key_free_temporary(void *ptr) {
965
319
    tcpcl_fragment_key_t *obj = (tcpcl_fragment_key_t *)ptr;
966
319
    if (obj) {
967
319
        addresses_ports_reassembly_table_functions.free_temporary_key_func(obj->addr_port);
968
319
        g_slice_free(tcpcl_fragment_key_t, obj);
969
319
    }
970
319
}
971
972
36
static void fragment_key_free_persistent(void *ptr) {
973
36
    tcpcl_fragment_key_t *obj = (tcpcl_fragment_key_t *)ptr;
974
36
    if (obj) {
975
36
        addresses_ports_reassembly_table_functions.free_persistent_key_func(obj->addr_port);
976
36
        g_slice_free(tcpcl_fragment_key_t, obj);
977
36
    }
978
36
}
979
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
987
};
988
989
/** Record metadata about one segment in a transfer.
990
 */
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
319
                                 proto_item *item_msg, proto_item *item_flags) {
995
319
    tcpcl_transfer_t *xfer = get_or_create_transfer_t(ctx->tx_peer->transfers, xfer_id);
996
997
319
    uint8_t flag_start, flag_end;
998
319
    if (ctx->tx_peer->version == 3) {
999
312
        flag_start = TCPCLV3_DATA_START_FLAG;
1000
312
        flag_end = TCPCLV3_DATA_END_FLAG;
1001
312
    }
1002
7
    else {
1003
7
        flag_start = TCPCLV4_TRANSFER_FLAG_START;
1004
7
        flag_end = TCPCLV4_TRANSFER_FLAG_END;
1005
7
    }
1006
1007
    // Add or get the segment metadata
1008
319
    tcpcl_seg_meta_t *seg_meta = tcpcl_seg_meta_new(pinfo, ctx->cur_loc);
1009
319
    wmem_list_frame_t *frm = wmem_list_find_custom(xfer->seg_list, seg_meta, tcpcl_seg_meta_compare_loc);
1010
319
    if (frm) {
1011
0
        tcpcl_seg_meta_free(seg_meta);
1012
0
        seg_meta = wmem_list_frame_data(frm);
1013
0
    }
1014
319
    else {
1015
319
        wmem_list_insert_sorted(xfer->seg_list, seg_meta, tcpcl_seg_meta_compare_loc);
1016
319
        frm = wmem_list_find_custom(xfer->seg_list, seg_meta, tcpcl_seg_meta_compare_loc);
1017
        // Set for new item
1018
319
        seg_meta->flags = flags;
1019
319
    }
1020
1021
    // mark start-of-transfer
1022
319
    if (!(seg_meta->related_start)) {
1023
319
        wmem_list_frame_t *frm_front = wmem_list_head(xfer->seg_list);
1024
319
        tcpcl_seg_meta_t *seg_front = frm_front ? wmem_list_frame_data(frm_front) : NULL;
1025
319
        if (seg_front && (seg_front->flags & flag_start)) {
1026
278
            seg_meta->related_start = seg_front;
1027
278
        }
1028
319
    }
1029
1030
    // accumulate segment sizes
1031
319
    uint64_t prev_seen_len;
1032
319
    wmem_list_frame_t *frm_prev = wmem_list_frame_prev(frm);
1033
319
    if (!frm_prev) {
1034
167
        if (!(flags & flag_start)) {
1035
40
            expert_add_info(pinfo, item_flags, &ei_tcpclv4_xfer_seg_missing_start);
1036
40
        }
1037
167
        prev_seen_len = 0;
1038
167
    }
1039
152
    else {
1040
152
        const tcpcl_seg_meta_t *seg_prev = wmem_list_frame_data(frm_prev);
1041
152
        if (flags & flag_start) {
1042
3
            expert_add_info(pinfo, item_flags, &ei_tcpclv4_xfer_seg_duplicate_start);
1043
3
        }
1044
152
        prev_seen_len = seg_prev->seen_len;
1045
152
    }
1046
319
    wmem_list_frame_t *frm_next = wmem_list_frame_next(frm);
1047
319
    if (!frm_next) {
1048
319
        if (!(flags & flag_end)) {
1049
135
            expert_add_info(pinfo, item_flags, &ei_tcpclv4_xfer_seg_missing_end);
1050
135
        }
1051
319
    }
1052
0
    else {
1053
0
        if (flags & flag_end) {
1054
0
            expert_add_info(pinfo, item_flags, &ei_tcpclv4_xfer_seg_duplicate_end);
1055
0
        }
1056
0
    }
1057
319
    seg_meta->seen_len = prev_seen_len + data_len;
1058
1059
319
    proto_item *item_seen = proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_segment_seen_len, tvb, 0, 0, seg_meta->seen_len);
1060
319
    proto_item_set_generated(item_seen);
1061
319
    if (seg_meta->seen_len > ctx->rx_peer->transfer_mru) {
1062
308
        expert_add_info(pinfo, item_seen, &ei_tcpclv4_xferload_over_xfer_mru);
1063
308
    }
1064
319
    if (xfer->total_length) {
1065
0
        if (seg_meta->seen_len > *(xfer->total_length)) {
1066
0
            expert_add_info(pinfo, item_seen, &ei_xfer_seg_over_total_len);
1067
0
        }
1068
0
        else if ((flags & flag_end)
1069
0
            && (seg_meta->seen_len != *(xfer->total_length))) {
1070
0
            expert_add_info(pinfo, item_seen, &ei_xfer_mismatch_total_len);
1071
0
        }
1072
0
        proto_item *item_total = proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_total_len, tvb, 0, 0, *(xfer->total_length));
1073
0
        proto_item_set_generated(item_total);
1074
0
    }
1075
1076
319
    if (seg_meta->related_ack) {
1077
0
        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
0
        proto_item_set_generated(item_rel);
1079
1080
0
        nstime_t td;
1081
0
        nstime_delta(&td, &(seg_meta->related_ack->frame_time), &(seg_meta->frame_time));
1082
0
        proto_item *item_td = proto_tree_add_time(tree_msg, hf_tcpclv4_xfer_segment_time_diff, tvb, 0, 0, &td);
1083
0
        proto_item_set_generated(item_td);
1084
1085
0
    }
1086
319
    else {
1087
319
        expert_add_info(pinfo, item_msg, &ei_tcpclv4_xfer_seg_no_relation);
1088
319
    }
1089
319
    if (seg_meta->related_start && (seg_meta->related_start != seg_meta)) {
1090
151
        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
151
        proto_item_set_generated(item_rel);
1092
1093
151
        nstime_t td;
1094
151
        nstime_delta(&td, &(seg_meta->frame_time), &(seg_meta->related_start->frame_time));
1095
151
        proto_item *item_td = proto_tree_add_time(tree_msg, hf_tcpclv4_xfer_segment_time_start, tvb, 0, 0, &td);
1096
151
        proto_item_set_generated(item_td);
1097
151
    }
1098
319
}
1099
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
1.13k
                             proto_item *item_msg, proto_item *item_flags) {
1104
1.13k
    tcpcl_transfer_t *xfer = get_or_create_transfer_t(ctx->rx_peer->transfers, xfer_id);
1105
1106
    // Add or get the ack metadata
1107
1.13k
    tcpcl_ack_meta_t *ack_meta = tcpcl_ack_meta_new(pinfo, ctx->cur_loc);
1108
1.13k
    wmem_list_frame_t *frm = wmem_list_find_custom(xfer->ack_list, ack_meta, tcpcl_ack_meta_compare_loc);
1109
1.13k
    if (frm) {
1110
1
        tcpcl_ack_meta_free(ack_meta);
1111
1
        ack_meta = wmem_list_frame_data(frm);
1112
1
    }
1113
1.12k
    else {
1114
1.12k
        wmem_list_insert_sorted(xfer->ack_list, ack_meta, tcpcl_ack_meta_compare_loc);
1115
1.12k
        wmem_list_find_custom(xfer->ack_list, ack_meta, tcpcl_ack_meta_compare_loc);
1116
        // Set for new item
1117
1.12k
        ack_meta->flags = flags;
1118
1.12k
        ack_meta->seen_len = ack_len;
1119
1.12k
    }
1120
1121
    // mark start-of-transfer
1122
1.13k
    if (!(ack_meta->related_start)) {
1123
1.13k
        wmem_list_frame_t *frm_front = wmem_list_head(xfer->seg_list);
1124
1.13k
        tcpcl_seg_meta_t *seg_front = frm_front ? wmem_list_frame_data(frm_front) : NULL;
1125
1.13k
        if (seg_front && (seg_front->flags & TCPCLV4_TRANSFER_FLAG_START)) {
1126
0
            ack_meta->related_start = seg_front;
1127
0
        }
1128
1.13k
    }
1129
1130
    // Assemble both of the links here, as ACK will always follow segment
1131
1.13k
    if (!(ack_meta->related_seg)) {
1132
1.13k
        wmem_list_frame_t *seg_iter = wmem_list_head(xfer->seg_list);
1133
1.13k
        for (; seg_iter; seg_iter = wmem_list_frame_next(seg_iter)) {
1134
0
            tcpcl_seg_meta_t *seg_meta = wmem_list_frame_data(seg_iter);
1135
0
            if (seg_meta->seen_len == ack_meta->seen_len) {
1136
0
                seg_meta->related_ack = ack_meta;
1137
0
                ack_meta->related_seg = seg_meta;
1138
0
            }
1139
0
        }
1140
1.13k
    }
1141
1142
1.13k
    if (xfer->total_length) {
1143
0
        proto_item *item_total = proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_total_len, tvb, 0, 0, *(xfer->total_length));
1144
0
        proto_item_set_generated(item_total);
1145
0
    }
1146
1.13k
    if (ack_meta->related_seg) {
1147
0
        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
0
        proto_item_set_generated(item_rel);
1149
1150
0
        nstime_t td;
1151
0
        nstime_delta(&td, &(ack_meta->frame_time), &(ack_meta->related_seg->frame_time));
1152
0
        proto_item *item_td = proto_tree_add_time(tree_msg, hf_tcpclv4_xfer_ack_time_diff, tvb, 0, 0, &td);
1153
0
        proto_item_set_generated(item_td);
1154
1155
0
        if (item_flags && (ack_meta->flags != ack_meta->related_seg->flags)) {
1156
0
            expert_add_info(pinfo, item_flags, &ei_xfer_ack_mismatch_flags);
1157
0
        }
1158
0
    }
1159
1.13k
    else {
1160
1.13k
        expert_add_info(pinfo, item_msg, &ei_xfer_ack_no_relation);
1161
1.13k
    }
1162
1.13k
    if (ack_meta->related_start) {
1163
0
        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
0
        proto_item_set_generated(item_rel);
1165
1166
0
        nstime_t td;
1167
0
        nstime_delta(&td, &(ack_meta->frame_time), &(ack_meta->related_start->frame_time));
1168
0
        proto_item *item_td = proto_tree_add_time(tree_msg, hf_tcpclv4_xfer_ack_time_start, tvb, 0, 0, &td);
1169
0
        proto_item_set_generated(item_td);
1170
0
    }
1171
1.13k
}
1172
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
1
                                proto_item *item_msg) {
1176
1
    const tcpcl_transfer_t *xfer = wmem_map_lookup(ctx->rx_peer->transfers, &xfer_id);
1177
1
    const tcpcl_seg_meta_t *seg_last = NULL;
1178
1
    if (xfer) {
1179
0
        wmem_list_frame_t *seg_iter = wmem_list_tail(xfer->seg_list);
1180
0
        seg_iter = seg_iter ? wmem_list_frame_prev(seg_iter) : NULL;
1181
0
        seg_last = seg_iter ? wmem_list_frame_data(seg_iter) : NULL;
1182
0
    }
1183
1184
1
    if (seg_last) {
1185
0
        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
0
        proto_item_set_generated(item_rel);
1187
0
    }
1188
1
    else {
1189
1
        expert_add_info(pinfo, item_msg, &ei_tcpclv4_xfer_refuse_no_transfer);
1190
1
    }
1191
1
}
1192
1193
679
static int get_clamped_length(uint64_t orig, packet_info *pinfo, proto_item *item) {
1194
679
    int clamped;
1195
679
    if (orig > INT_MAX) {
1196
13
        clamped = INT_MAX;
1197
13
        if (pinfo && item) {
1198
0
            expert_add_info(pinfo, item, &ei_length_clamped);
1199
0
        }
1200
13
    }
1201
666
    else {
1202
666
        clamped = (int) orig;
1203
666
    }
1204
679
    return clamped;
1205
679
}
1206
1207
static unsigned
1208
get_v3_msg_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset,
1209
               tcpcl_dissect_ctx_t *ctx _U_)
1210
4.00k
{
1211
4.00k
    const int orig_offset = offset;
1212
4.00k
    uint64_t len;
1213
4.00k
    unsigned bytecount;
1214
4.00k
    uint8_t conv_hdr = tvb_get_uint8(tvb, offset);
1215
4.00k
    offset += 1;
1216
1217
4.00k
    switch (conv_hdr & TCPCLV3_TYPE_MASK)
1218
4.00k
    {
1219
327
    case TCPCLV3_DATA_SEGMENT: {
1220
        /* get length from sdnv */
1221
327
        bytecount = tvb_get_sdnv(tvb, offset, &len);
1222
327
        if (bytecount == 0) {
1223
1
            return 0;
1224
1
        }
1225
326
        const int len_clamp = get_clamped_length(len, NULL, NULL);
1226
326
        offset += bytecount + len_clamp;
1227
326
        break;
1228
327
    }
1229
1.10k
    case TCPCLV3_ACK_SEGMENT:
1230
        /* get length from sdnv */
1231
1.10k
        bytecount = tvb_get_sdnv(tvb, offset, &len);
1232
1.10k
        if (bytecount == 0) {
1233
1
            return 0;
1234
1
        }
1235
1.10k
        offset += bytecount;
1236
1.10k
        break;
1237
1238
476
    case TCPCLV3_KEEP_ALIVE:
1239
1.40k
    case TCPCLV3_REFUSE_BUNDLE:
1240
        /* always 1 byte */
1241
1.40k
        break;
1242
648
    case TCPCLV3_SHUTDOWN:
1243
648
        if (conv_hdr & TCPCLV3_SHUTDOWN_REASON) {
1244
138
            offset += 1;
1245
138
        }
1246
648
        if (conv_hdr & TCPCLV3_SHUTDOWN_DELAY) {
1247
124
            offset += 2;
1248
124
        }
1249
648
        break;
1250
1251
440
    case TCPCLV3_LENGTH:
1252
        /* get length from sdnv */
1253
440
        bytecount = tvb_get_sdnv(tvb, offset, &len);
1254
440
        if (bytecount == 0) {
1255
1
            return 0;
1256
1
        }
1257
439
        offset += bytecount;
1258
439
        break;
1259
1260
81
    default:
1261
        // no known message
1262
81
        return 0;
1263
4.00k
    }
1264
1265
3.91k
    return offset - orig_offset;
1266
4.00k
}
1267
1268
static int
1269
dissect_v3_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1270
               tcpcl_dissect_ctx_t *ctx)
1271
3.91k
{
1272
3.91k
    uint8_t        conv_hdr;
1273
3.91k
    const char *msgtype_name;
1274
3.91k
    uint8_t        refuse_bundle_hdr;
1275
3.91k
    int            offset = 0;
1276
3.91k
    int sdnv_length;
1277
3.91k
    uint64_t segment_length;
1278
3.91k
    proto_item    *conv_item, *sub_item;
1279
3.91k
    proto_tree    *conv_tree, *sub_tree;
1280
3.91k
    uint64_t *xfer_id = NULL;
1281
3.91k
    proto_item *item_xfer_id = NULL;
1282
1283
3.91k
    conv_item = proto_tree_add_item(tree, hf_tcpclv3_mhdr, tvb, 0, -1, ENC_NA);
1284
3.91k
    conv_tree = proto_item_add_subtree(conv_item, ett_tcpclv3_mhdr);
1285
1286
3.91k
    conv_hdr = tvb_get_uint8(tvb, offset);
1287
3.91k
    proto_tree_add_item(conv_tree, hf_tcpclv3_pkt_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1288
1289
3.91k
    msgtype_name = val_to_str_const((conv_hdr>>4)&0xF, v3_message_type_vals, "Unknown");
1290
3.91k
    col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, msgtype_name);
1291
3.91k
    proto_item_append_text(proto_tree_get_parent(conv_tree), ": %s", msgtype_name);
1292
1293
3.91k
    switch (conv_hdr & TCPCLV3_TYPE_MASK) {
1294
323
    case TCPCLV3_DATA_SEGMENT: {
1295
323
        proto_item *item_flags;
1296
1297
323
        item_flags = proto_tree_add_bitmask(
1298
323
            conv_tree, tvb,
1299
323
            offset, hf_tcpclv3_data_procflags,
1300
323
            ett_tcpclv3_data_procflags, v3_data_procflags,
1301
323
            ENC_BIG_ENDIAN
1302
323
        );
1303
323
        offset += 1;
1304
1305
        /* Only Start and End flags (bits 0 & 1) are valid in Data Segment */
1306
323
        if ((conv_hdr & ~(TCPCLV3_TYPE_MASK | TCPCLV3_DATA_FLAGS)) != 0) {
1307
227
            expert_add_info(pinfo, item_flags, &ei_tcpclv3_data_flags);
1308
227
        }
1309
1310
323
        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
323
        if (sdnv_length == 0) {
1312
0
            expert_add_info(pinfo, sub_item, &ei_tcpclv3_segment_length);
1313
0
            return 0;
1314
0
        }
1315
323
        offset += sdnv_length;
1316
323
        const int data_len_clamp = get_clamped_length(segment_length, pinfo, sub_item);
1317
1318
        // implied transfer ID
1319
323
        xfer_id = wmem_map_lookup(ctx->tx_peer->frame_loc_to_transfer, ctx->cur_loc);
1320
323
        if (!xfer_id) {
1321
323
            xfer_id = wmem_new(wmem_packet_scope(), uint64_t);
1322
323
            *xfer_id = wmem_map_size(ctx->tx_peer->transfers);
1323
1324
323
            if (conv_hdr & TCPCLV3_DATA_START_FLAG) {
1325
133
                *xfer_id += 1;
1326
133
                get_or_create_transfer_t(ctx->tx_peer->transfers, *xfer_id);
1327
133
            }
1328
323
            tcpcl_peer_associate_transfer(ctx->tx_peer, ctx->cur_loc, *xfer_id);
1329
323
        }
1330
323
        item_xfer_id = proto_tree_add_uint64(conv_tree, hf_tcpclv3_xfer_id, tvb, 0, 0, *xfer_id);
1331
323
        proto_item_set_generated(item_xfer_id);
1332
1333
323
        proto_tree_add_item(conv_tree, hf_tcpclv3_data_segment_data, tvb, offset, data_len_clamp, ENC_NA);
1334
1335
323
        if (tcpcl_analyze_sequence) {
1336
312
            transfer_add_segment(ctx, *xfer_id, (conv_hdr & TCPCLV3_DATA_FLAGS), segment_length, pinfo, tvb, conv_tree, conv_item, item_flags);
1337
312
        }
1338
1339
323
        if (tcpcl_desegment_transfer) {
1340
            // Reassemble the segments
1341
312
            fragment_head *frag_msg;
1342
312
            frag_msg = fragment_add_seq_next(
1343
312
                &xfer_reassembly_table,
1344
312
                tvb, offset,
1345
312
                pinfo, 0, xfer_id,
1346
312
                data_len_clamp,
1347
312
                !(conv_hdr & TCPCLV3_DATA_END_FLAG)
1348
312
            );
1349
312
            ctx->xferload = process_reassembled_data(
1350
312
                tvb, offset, pinfo,
1351
312
                "Reassembled Transfer",
1352
312
                frag_msg,
1353
312
                &xfer_frag_items,
1354
312
                NULL,
1355
312
                proto_tree_get_parent_tree(tree)
1356
312
            );
1357
312
        }
1358
323
        offset += data_len_clamp;
1359
1360
323
        break;
1361
323
    }
1362
1.10k
    case TCPCLV3_ACK_SEGMENT: {
1363
        /*No valid flags*/
1364
1.10k
        offset += 1;
1365
1366
1.10k
        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
1.10k
        if (sdnv_length == 0) {
1368
0
            expert_add_info(pinfo, sub_item, &ei_tcpclv3_ack_length);
1369
1.10k
        } else {
1370
1.10k
            offset += sdnv_length;
1371
1.10k
        }
1372
1373
        // implied transfer ID
1374
1.10k
        xfer_id = wmem_map_lookup(ctx->rx_peer->frame_loc_to_transfer, ctx->cur_loc);
1375
1.10k
        if (!xfer_id) {
1376
1.09k
            xfer_id = wmem_new(wmem_packet_scope(), uint64_t);
1377
1.09k
            *xfer_id = wmem_map_size(ctx->rx_peer->transfers);
1378
1379
1.09k
            tcpcl_peer_associate_transfer(ctx->rx_peer, ctx->cur_loc, *xfer_id);
1380
1.09k
        }
1381
1.10k
        item_xfer_id = proto_tree_add_uint64(conv_tree, hf_tcpclv3_xfer_id, tvb, 0, 0, *xfer_id);
1382
1.10k
        proto_item_set_generated(item_xfer_id);
1383
1384
1.10k
        if (tcpcl_analyze_sequence) {
1385
1.10k
            transfer_add_ack(ctx, *xfer_id, 0, segment_length, pinfo, tvb, conv_tree, conv_item, NULL);
1386
1.10k
        }
1387
1388
1.10k
        break;
1389
323
    }
1390
476
    case TCPCLV3_KEEP_ALIVE:
1391
        /*No valid flags in Keep Alive*/
1392
476
        offset += 1;
1393
476
        break;
1394
1395
648
    case TCPCLV3_SHUTDOWN:
1396
        /* Add tree for Shutdown Flags */
1397
648
        sub_item = proto_tree_add_item(conv_tree, hf_tcpclv3_shutdown_flags, tvb,
1398
648
                                        offset, 1, ENC_BIG_ENDIAN);
1399
648
        sub_tree = proto_item_add_subtree(sub_item, ett_tcpclv3_shutdown_flags);
1400
1401
648
        proto_tree_add_item(sub_tree, hf_tcpclv3_shutdown_flags_reason,
1402
648
                            tvb, offset, 1, ENC_BIG_ENDIAN);
1403
648
        proto_tree_add_item(sub_tree, hf_tcpclv3_shutdown_flags_delay,
1404
648
                            tvb, offset, 1, ENC_BIG_ENDIAN);
1405
1406
648
        offset += 1;
1407
648
        if (conv_hdr & TCPCLV3_SHUTDOWN_REASON) {
1408
138
            proto_tree_add_item(conv_tree,
1409
138
                                hf_tcpclv3_shutdown_reason, tvb,
1410
138
                                offset, 1, ENC_BIG_ENDIAN);
1411
138
            offset += 1;
1412
138
        }
1413
648
        if (conv_hdr & TCPCLV3_SHUTDOWN_DELAY) {
1414
124
            proto_tree_add_item(conv_tree,
1415
124
                                hf_tcpclv3_shutdown_delay, tvb,
1416
124
                                offset, 2, ENC_BIG_ENDIAN);
1417
124
            offset += 1;
1418
124
        }
1419
648
        break;
1420
928
    case TCPCLV3_REFUSE_BUNDLE:
1421
        /*No valid flags*/
1422
928
        offset += 1;
1423
1424
928
        refuse_bundle_hdr = tvb_get_uint8(tvb, offset);
1425
928
        proto_tree_add_item(conv_tree, hf_tcpclv3_refuse_reason_code, tvb, offset, 1, ENC_BIG_ENDIAN);
1426
928
        offset += 1;
1427
928
        col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const((refuse_bundle_hdr>>4)&0xF, v3_refuse_reason_code, "Unknown"));
1428
1429
        // implied transfer ID
1430
928
        xfer_id = wmem_map_lookup(ctx->rx_peer->frame_loc_to_transfer, ctx->cur_loc);
1431
928
        if (!xfer_id) {
1432
0
            xfer_id = wmem_new(wmem_packet_scope(), uint64_t);
1433
0
            *xfer_id = wmem_map_size(ctx->rx_peer->transfers);
1434
1435
0
            tcpcl_peer_associate_transfer(ctx->rx_peer, ctx->cur_loc, *xfer_id);
1436
0
        }
1437
928
        item_xfer_id = proto_tree_add_uint64(conv_tree, hf_tcpclv3_xfer_id, tvb, 0, 0, *xfer_id);
1438
928
        proto_item_set_generated(item_xfer_id);
1439
1440
928
        if (tcpcl_analyze_sequence) {
1441
0
            transfer_add_refuse(ctx, *xfer_id, pinfo, tvb, conv_tree, conv_item);
1442
0
        }
1443
1444
928
        break;
1445
1446
439
    default:
1447
439
        expert_add_info(pinfo, proto_tree_get_parent(conv_tree), &ei_tcpclv3_invalid_msg_type);
1448
439
        break;
1449
3.91k
    }
1450
1451
2.97k
    return offset;
1452
3.91k
}
1453
1454
static unsigned get_v4_msg_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset,
1455
159
                            tcpcl_dissect_ctx_t *ctx _U_) {
1456
159
    const int init_offset = offset;
1457
159
    uint8_t msgtype = tvb_get_uint8(tvb, offset);
1458
159
    offset += 1;
1459
159
    switch(msgtype) {
1460
0
        case TCPCLV4_MSGTYPE_SESS_INIT: {
1461
0
            const int buflen = tvb_reported_length(tvb);
1462
0
            offset += 2 + 8 + 8;
1463
0
            if (buflen < offset + 2) {
1464
0
                return 0;
1465
0
            }
1466
0
            uint16_t nodeid_len = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
1467
0
            offset += 2;
1468
0
            offset += nodeid_len;
1469
0
            if (buflen < offset + 4) {
1470
0
                return 0;
1471
0
            }
1472
0
            uint32_t extlist_len = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
1473
0
            offset += 4;
1474
0
            offset += extlist_len;
1475
0
            break;
1476
0
        }
1477
0
        case TCPCLV4_MSGTYPE_SESS_TERM: {
1478
0
            offset += 1 + 1;
1479
0
            break;
1480
0
        }
1481
27
        case TCPCLV4_MSGTYPE_XFER_SEGMENT: {
1482
27
            const int buflen = tvb_reported_length(tvb);
1483
27
            if (buflen < offset + 1) {
1484
0
                return 0;
1485
0
            }
1486
27
            uint8_t flags = tvb_get_uint8(tvb, offset);
1487
27
            offset += 1;
1488
27
            offset += 8;
1489
27
            if (flags & TCPCLV4_TRANSFER_FLAG_START) {
1490
14
                if (buflen < offset + 4) {
1491
0
                    return 0;
1492
0
                }
1493
14
                uint32_t extlist_len = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
1494
14
                offset += 4;
1495
14
                offset += extlist_len;
1496
14
            }
1497
27
            if (buflen < offset + 8) {
1498
8
                return 0;
1499
8
            }
1500
19
            uint64_t data_len = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
1501
19
            offset += 8;
1502
19
            const int data_len_clamp = get_clamped_length(data_len, NULL, NULL);
1503
19
            offset += data_len_clamp;
1504
19
            break;
1505
27
        }
1506
32
        case TCPCLV4_MSGTYPE_XFER_ACK: {
1507
32
            offset += 1 + 8 + 8;
1508
32
            break;
1509
27
        }
1510
1
        case TCPCLV4_MSGTYPE_XFER_REFUSE: {
1511
1
            offset += 1 + 8;
1512
1
            break;
1513
27
        }
1514
24
        case TCPCLV4_MSGTYPE_KEEPALIVE: {
1515
24
            break;
1516
27
        }
1517
1
        case TCPCLV4_MSGTYPE_MSG_REJECT: {
1518
1
            offset += 1 + 1;
1519
1
            break;
1520
27
        }
1521
74
        default:
1522
            // no known message
1523
74
            return 0;
1524
159
    }
1525
77
    return offset - init_offset;
1526
159
}
1527
1528
static int
1529
dissect_v4_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1530
67
               tcpcl_dissect_ctx_t *ctx _U_) {
1531
67
    int offset  = 0;
1532
    // Length of non-protocol 'payload' data in this message
1533
67
    int payload_len = 0;
1534
1535
67
    uint8_t msgtype = 0;
1536
67
    const char *msgtype_name = NULL;
1537
1538
67
    proto_item *item_msg = proto_tree_add_item(tree, hf_tcpclv4_mhdr_tree, tvb, offset, 0, ENC_NA);
1539
67
    proto_tree *tree_msg = proto_item_add_subtree(item_msg, ett_tcpclv4_mhdr);
1540
1541
67
    msgtype = tvb_get_uint8(tvb, offset);
1542
67
    proto_tree_add_uint(tree_msg, hf_tcpclv4_mhdr_type, tvb, offset, 1, msgtype);
1543
67
    offset += 1;
1544
67
    msgtype_name = val_to_str(msgtype, v4_message_type_vals, "type 0x%02" PRIx32);
1545
67
    wmem_strbuf_t *suffix_text = wmem_strbuf_new(wmem_packet_scope(), NULL);
1546
1547
67
    switch(msgtype) {
1548
0
        case TCPCLV4_MSGTYPE_SESS_INIT: {
1549
0
            uint16_t keepalive = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
1550
0
            proto_tree_add_uint(tree_msg, hf_tcpclv4_sess_init_keepalive, tvb, offset, 2, keepalive);
1551
0
            offset += 2;
1552
1553
0
            uint64_t seg_mru = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
1554
0
            proto_tree_add_uint64(tree_msg, hf_tcpclv4_sess_init_seg_mru, tvb, offset, 8, seg_mru);
1555
0
            offset += 8;
1556
1557
0
            uint64_t xfer_mru = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
1558
0
            proto_tree_add_uint64(tree_msg, hf_tcpclv4_sess_init_xfer_mru, tvb, offset, 8, xfer_mru);
1559
0
            offset += 8;
1560
1561
0
            uint16_t nodeid_len = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
1562
0
            proto_tree_add_uint(tree_msg, hf_tcpclv4_sess_init_nodeid_len, tvb, offset, 2, nodeid_len);
1563
0
            offset += 2;
1564
1565
0
            {
1566
0
                uint8_t *nodeid_data = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, nodeid_len, ENC_UTF_8);
1567
0
                proto_tree_add_string(tree_msg, hf_tcpclv4_sess_init_nodeid_data, tvb, offset, nodeid_len, (const char *)nodeid_data);
1568
0
                wmem_free(wmem_packet_scope(), nodeid_data);
1569
0
            }
1570
0
            offset += nodeid_len;
1571
1572
0
            uint32_t extlist_len = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
1573
0
            proto_tree_add_uint(tree_msg, hf_tcpclv4_sess_init_extlist_len, tvb, offset, 4, extlist_len);
1574
0
            offset += 4;
1575
1576
0
            int extlist_offset = 0;
1577
0
            while (extlist_offset < (int)extlist_len) {
1578
0
                int extitem_offset = 0;
1579
0
                proto_item *item_ext = proto_tree_add_item(tree_msg, hf_tcpclv4_sessext_tree, tvb, offset + extlist_offset, 0, ENC_NA);
1580
0
                proto_tree *tree_ext = proto_item_add_subtree(item_ext, ett_tcpclv4_sessext);
1581
1582
0
                uint8_t extitem_flags = tvb_get_uint8(tvb, offset + extlist_offset + extitem_offset);
1583
0
                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
0
                extitem_offset += 1;
1585
0
                const bool is_critical = (extitem_flags & TCPCLV4_EXTENSION_FLAG_CRITICAL);
1586
0
                if (is_critical) {
1587
0
                    expert_add_info(pinfo, item_ext, &ei_tcpclv4_extitem_critical);
1588
0
                }
1589
1590
0
                uint16_t extitem_type = tvb_get_uint16(tvb, offset + extlist_offset + extitem_offset, ENC_BIG_ENDIAN);
1591
0
                proto_item *item_type = proto_tree_add_uint(tree_ext, hf_tcpclv4_sessext_type, tvb, offset + extlist_offset + extitem_offset, 2, extitem_type);
1592
0
                extitem_offset += 2;
1593
1594
0
                dissector_handle_t subdis = dissector_get_uint_handle(xfer_ext_dissectors, extitem_type);
1595
0
                const char *subname = dissector_handle_get_description(subdis);
1596
0
                if (subdis) {
1597
0
                    proto_item_set_text(item_type, "Item Type: %s (0x%04" PRIx16 ")", subname, extitem_type);
1598
0
                }
1599
1600
0
                uint16_t extitem_len = tvb_get_uint16(tvb, offset + extlist_offset + extitem_offset, ENC_BIG_ENDIAN);
1601
0
                proto_tree_add_uint(tree_ext, hf_tcpclv4_sessext_len, tvb, offset + extlist_offset + extitem_offset, 2, extitem_len);
1602
0
                extitem_offset += 2;
1603
1604
0
                tvbuff_t *extitem_tvb = tvb_new_subset_length(tvb, offset + extlist_offset + extitem_offset, extitem_len);
1605
0
                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
0
                proto_tree *tree_extdata = proto_item_add_subtree(item_extdata, ett_tcpclv4_sessext_data);
1607
1608
0
                int sublen = 0;
1609
0
                if (subdis) {
1610
0
                    sublen = call_dissector_only(subdis, extitem_tvb, pinfo, tree_extdata, NULL);
1611
0
                }
1612
0
                if (sublen == 0) {
1613
0
                    expert_add_info(pinfo, item_type, &ei_tcpclv4_invalid_sessext_type);
1614
0
                }
1615
0
                extitem_offset += extitem_len;
1616
1617
0
                proto_item_set_len(item_ext, extitem_offset);
1618
0
                extlist_offset += extitem_offset;
1619
1620
0
                if (subname) {
1621
0
                    proto_item_append_text(item_ext, ": %s", subname);
1622
0
                }
1623
0
                else {
1624
0
                    proto_item_append_text(item_ext, ": Type 0x%04" PRIx16, extitem_type);
1625
0
                }
1626
0
                if (is_critical) {
1627
0
                    proto_item_append_text(item_ext, ", CRITICAL");
1628
0
                }
1629
0
            }
1630
            // advance regardless of any internal offset processing
1631
0
            offset += extlist_len;
1632
1633
0
            if (ctx->tx_peer->sess_init_seen) {
1634
0
                if (tcpcl_analyze_sequence) {
1635
0
                    if (!tcpcl_frame_loc_equal(ctx->tx_peer->sess_init_seen, ctx->cur_loc)) {
1636
0
                        expert_add_info(pinfo, item_msg, &ei_tcpclv4_sess_init_duplicate);
1637
0
                    }
1638
0
                }
1639
0
            }
1640
0
            else {
1641
0
                ctx->tx_peer->sess_init_seen = tcpcl_frame_loc_clone(wmem_file_scope(), ctx->cur_loc);
1642
0
                ctx->tx_peer->keepalive = keepalive;
1643
0
                ctx->tx_peer->segment_mru = seg_mru;
1644
0
                ctx->tx_peer->transfer_mru = xfer_mru;
1645
0
            }
1646
1647
0
            break;
1648
0
        }
1649
0
        case TCPCLV4_MSGTYPE_SESS_TERM: {
1650
0
            uint8_t flags = tvb_get_uint8(tvb, offset);
1651
0
            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
0
            offset += 1;
1653
1654
0
            uint8_t reason = tvb_get_uint8(tvb, offset);
1655
0
            proto_tree_add_uint(tree_msg, hf_tcpclv4_sess_term_reason, tvb, offset, 1, reason);
1656
0
            offset += 1;
1657
1658
0
            if (ctx->tx_peer->sess_term_seen) {
1659
0
                if (tcpcl_analyze_sequence) {
1660
0
                    if (!tcpcl_frame_loc_equal(ctx->tx_peer->sess_term_seen, ctx->cur_loc)) {
1661
0
                        expert_add_info(pinfo, item_msg, &ei_tcpclv4_sess_term_duplicate);
1662
0
                    }
1663
0
                }
1664
0
            }
1665
0
            else {
1666
0
                ctx->tx_peer->sess_term_seen = tcpcl_frame_loc_clone(wmem_file_scope(), ctx->cur_loc);
1667
0
                ctx->tx_peer->sess_term_reason = reason;
1668
0
            }
1669
1670
0
            if (tcpcl_analyze_sequence) {
1671
0
                if (ctx->rx_peer->sess_term_seen) {
1672
0
                    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
0
                    proto_item_set_generated(item_rel);
1674
1675
                    // Is this message after the other SESS_TERM?
1676
0
                    if (tcpcl_frame_loc_compare(ctx->tx_peer->sess_term_seen, ctx->rx_peer->sess_term_seen, NULL) > 0) {
1677
0
                        if (!(flags & TCPCLV4_SESS_TERM_FLAG_REPLY)) {
1678
0
                            expert_add_info(pinfo, item_msg, &ei_tcpclv4_sess_term_reply_flag);
1679
0
                        }
1680
0
                    }
1681
0
                }
1682
0
            }
1683
1684
0
            break;
1685
0
        }
1686
9
        case TCPCLV4_MSGTYPE_XFER_SEGMENT:{
1687
9
            uint8_t flags = tvb_get_uint8(tvb, offset);
1688
9
            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
9
            offset += 1;
1690
1691
9
            uint64_t xfer_id = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
1692
9
            proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_id, tvb, offset, 8, xfer_id);
1693
9
            offset += 8;
1694
1695
9
            if (flags & TCPCLV4_TRANSFER_FLAG_START) {
1696
6
                uint32_t extlist_len = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
1697
6
                proto_tree_add_uint(tree_msg, hf_tcpclv4_xfer_segment_extlist_len, tvb, offset, 4, extlist_len);
1698
6
                offset += 4;
1699
1700
6
                int extlist_offset = 0;
1701
8
                while (extlist_offset < (int)extlist_len) {
1702
2
                    int extitem_offset = 0;
1703
2
                    proto_item *item_ext = proto_tree_add_item(tree_msg, hf_tcpclv4_xferext_tree, tvb, offset + extlist_offset, 0, ENC_NA);
1704
2
                    proto_tree *tree_ext = proto_item_add_subtree(item_ext, ett_tcpclv4_xferext);
1705
1706
2
                    uint8_t extitem_flags = tvb_get_uint8(tvb, offset + extlist_offset + extitem_offset);
1707
2
                    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
2
                    extitem_offset += 1;
1709
2
                    const bool is_critical = (extitem_flags & TCPCLV4_EXTENSION_FLAG_CRITICAL);
1710
2
                    if (is_critical) {
1711
2
                        expert_add_info(pinfo, item_ext, &ei_tcpclv4_extitem_critical);
1712
2
                    }
1713
1714
2
                    uint16_t extitem_type = tvb_get_uint16(tvb, offset + extlist_offset + extitem_offset, ENC_BIG_ENDIAN);
1715
2
                    proto_item *item_type = proto_tree_add_uint(tree_ext, hf_tcpclv4_xferext_type, tvb, offset + extlist_offset + extitem_offset, 2, extitem_type);
1716
2
                    extitem_offset += 2;
1717
1718
2
                    dissector_handle_t subdis = dissector_get_uint_handle(xfer_ext_dissectors, extitem_type);
1719
2
                    const char *subname = dissector_handle_get_description(subdis);
1720
2
                    if (subdis) {
1721
0
                        proto_item_set_text(item_type, "Item Type: %s (0x%04" PRIx16 ")", subname, extitem_type);
1722
0
                    }
1723
1724
2
                    uint16_t extitem_len = tvb_get_uint16(tvb, offset + extlist_offset + extitem_offset, ENC_BIG_ENDIAN);
1725
2
                    proto_tree_add_uint(tree_ext, hf_tcpclv4_xferext_len, tvb, offset + extlist_offset + extitem_offset, 2, extitem_len);
1726
2
                    extitem_offset += 2;
1727
1728
2
                    tvbuff_t *extitem_tvb = tvb_new_subset_length(tvb, offset + extlist_offset + extitem_offset, extitem_len);
1729
2
                    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
2
                    proto_tree *tree_extdata = proto_item_add_subtree(item_extdata, ett_tcpclv4_xferext_data);
1731
1732
2
                    tcpcl_frame_loc_t *extitem_loc = tcpcl_frame_loc_new(wmem_packet_scope(), pinfo, extitem_tvb, 0);
1733
2
                    tcpcl_peer_associate_transfer(ctx->tx_peer, extitem_loc, xfer_id);
1734
1735
2
                    int sublen = 0;
1736
2
                    if (subdis) {
1737
0
                        sublen = call_dissector_only(subdis, extitem_tvb, pinfo, tree_extdata, NULL);
1738
0
                    }
1739
2
                    if (sublen == 0) {
1740
2
                        expert_add_info(pinfo, item_type, &ei_tcpclv4_invalid_xferext_type);
1741
2
                    }
1742
2
                    extitem_offset += extitem_len;
1743
1744
2
                    proto_item_set_len(item_ext, extitem_offset);
1745
2
                    extlist_offset += extitem_offset;
1746
1747
2
                    if (subname) {
1748
0
                        proto_item_append_text(item_ext, ": %s", subname);
1749
0
                    }
1750
2
                    else {
1751
2
                        proto_item_append_text(item_ext, ": Type 0x%04" PRIx16, extitem_type);
1752
2
                    }
1753
2
                    if (is_critical) {
1754
2
                        proto_item_append_text(item_ext, ", CRITICAL");
1755
2
                    }
1756
2
                }
1757
                // advance regardless of any internal offset processing
1758
6
                offset += extlist_len;
1759
6
            }
1760
1761
9
            uint64_t data_len = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
1762
9
            proto_item *item_len = proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_segment_data_len, tvb, offset, 8, data_len);
1763
9
            offset += 8;
1764
1765
9
            if (data_len > ctx->rx_peer->segment_mru) {
1766
4
                expert_add_info(pinfo, item_len, &ei_tcpclv4_xfer_seg_over_seg_mru);
1767
4
            }
1768
9
            const int data_len_clamp = get_clamped_length(data_len, pinfo, item_len);
1769
1770
            // Treat data as payload layer
1771
9
            const int data_offset = offset;
1772
9
            proto_tree_add_item(tree_msg, hf_tcpclv4_xfer_segment_data, tvb, offset, data_len_clamp, ENC_NA);
1773
9
            offset += data_len_clamp;
1774
9
            payload_len = data_len_clamp;
1775
1776
9
            wmem_strbuf_append_printf(suffix_text, ", Xfer ID: %" PRIi64, xfer_id);
1777
1778
9
            if (flags) {
1779
6
                wmem_strbuf_append(suffix_text, ", Flags: ");
1780
6
                bool sep = false;
1781
6
                if (flags & TCPCLV4_TRANSFER_FLAG_START) {
1782
5
                    wmem_strbuf_append(suffix_text, "START");
1783
5
                    sep = true;
1784
5
                }
1785
6
                if (flags & TCPCLV4_TRANSFER_FLAG_END) {
1786
0
                    if (sep) {
1787
0
                        wmem_strbuf_append(suffix_text, "|");
1788
0
                    }
1789
0
                    wmem_strbuf_append(suffix_text, "END");
1790
0
                }
1791
6
            }
1792
1793
9
            if (tcpcl_analyze_sequence) {
1794
7
                transfer_add_segment(ctx, xfer_id, flags, data_len, pinfo, tvb, tree_msg, item_msg, item_flags);
1795
7
            }
1796
1797
9
            if (tcpcl_desegment_transfer) {
1798
                // Reassemble the segments
1799
7
                fragment_head *xferload_frag_msg = fragment_add_seq_next(
1800
7
                    &xfer_reassembly_table,
1801
7
                    tvb, data_offset,
1802
7
                    pinfo, 0, &xfer_id,
1803
7
                    data_len_clamp,
1804
7
                    !(flags & TCPCLV4_TRANSFER_FLAG_END)
1805
7
                );
1806
7
                ctx->xferload = process_reassembled_data(
1807
7
                    tvb, data_offset, pinfo,
1808
7
                    "Reassembled Transfer",
1809
7
                    xferload_frag_msg,
1810
7
                    &xfer_frag_items,
1811
7
                    NULL,
1812
7
                    proto_tree_get_parent_tree(tree)
1813
7
                );
1814
7
            }
1815
1816
9
            break;
1817
0
        }
1818
32
        case TCPCLV4_MSGTYPE_XFER_ACK:{
1819
32
            uint8_t flags = tvb_get_uint8(tvb, offset);
1820
32
            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
32
            offset += 1;
1822
1823
32
            uint64_t xfer_id = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
1824
32
            proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_id, tvb, offset, 8, xfer_id);
1825
32
            offset += 8;
1826
1827
32
            uint64_t ack_len = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
1828
32
            proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_ack_ack_len, tvb, offset, 8, ack_len);
1829
32
            offset += 8;
1830
1831
32
            wmem_strbuf_append_printf(suffix_text, ", Xfer ID: %" PRIi64, xfer_id);
1832
1833
32
            if (flags) {
1834
29
                wmem_strbuf_append(suffix_text, ", Flags: ");
1835
29
                bool sep = false;
1836
29
                if (flags & TCPCLV4_TRANSFER_FLAG_START) {
1837
28
                    wmem_strbuf_append(suffix_text, "START");
1838
28
                    sep = true;
1839
28
                }
1840
29
                if (flags & TCPCLV4_TRANSFER_FLAG_END) {
1841
1
                    if (sep) {
1842
1
                        wmem_strbuf_append(suffix_text, "|");
1843
1
                    }
1844
1
                    wmem_strbuf_append(suffix_text, "END");
1845
1
                }
1846
29
            }
1847
1848
32
            if (tcpcl_analyze_sequence) {
1849
30
                transfer_add_ack(ctx, xfer_id, flags, ack_len, pinfo, tvb, tree_msg, item_msg, item_flags);
1850
30
            }
1851
1852
32
            break;
1853
0
        }
1854
1
        case TCPCLV4_MSGTYPE_XFER_REFUSE: {
1855
1
            uint8_t reason = tvb_get_uint8(tvb, offset);
1856
1
            proto_tree_add_uint(tree_msg, hf_tcpclv4_xfer_refuse_reason, tvb, offset, 1, reason);
1857
1
            offset += 1;
1858
1859
1
            uint64_t xfer_id = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
1860
1
            proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_id, tvb, offset, 8, xfer_id);
1861
1
            offset += 8;
1862
1863
1
            wmem_strbuf_append_printf(suffix_text, ", Xfer ID: %" PRIi64, xfer_id);
1864
1865
1
            if (tcpcl_analyze_sequence) {
1866
1
                transfer_add_refuse(ctx, xfer_id, pinfo, tvb, tree_msg, item_msg);
1867
1
            }
1868
1869
1
            break;
1870
0
        }
1871
24
        case TCPCLV4_MSGTYPE_KEEPALIVE: {
1872
24
            break;
1873
0
        }
1874
1
        case TCPCLV4_MSGTYPE_MSG_REJECT: {
1875
1
            uint8_t reason = tvb_get_uint8(tvb, offset);
1876
1
            proto_tree_add_uint(tree_msg, hf_tcpclv4_msg_reject_reason, tvb, offset, 1, reason);
1877
1
            offset += 1;
1878
1879
1
            uint8_t rej_head = tvb_get_uint8(tvb, offset);
1880
1
            proto_tree_add_uint(tree_msg, hf_tcpclv4_msg_reject_head, tvb, offset, 1, rej_head);
1881
1
            offset += 1;
1882
1883
1
            break;
1884
0
        }
1885
0
        default:
1886
0
            expert_add_info(pinfo, item_msg, &ei_tcpclv4_invalid_msg_type);
1887
0
            break;
1888
67
    }
1889
1890
63
    proto_item_set_len(item_msg, offset - payload_len);
1891
63
    proto_item_append_text(item_msg, ": %s%s", msgtype_name, wmem_strbuf_get_str(suffix_text));
1892
63
    wmem_strbuf_finalize(suffix_text);
1893
1894
63
    if (tcpcl_analyze_sequence) {
1895
63
        if (!(ctx->tx_peer->chdr_missing)) {
1896
            // assume the capture is somewhere in the middle
1897
24
            if (!(ctx->tx_peer->sess_init_seen)) {
1898
24
                expert_add_info(pinfo, item_msg, &ei_tcpclv4_sess_init_missing);
1899
24
            }
1900
0
            else {
1901
                // This message is before SESS_INIT (but is not the SESS_INIT)
1902
0
                const int cmp_sess_init = tcpcl_frame_loc_compare(ctx->cur_loc, ctx->tx_peer->sess_init_seen, NULL);
1903
0
                if (((msgtype == TCPCLV4_MSGTYPE_SESS_INIT) && (cmp_sess_init < 0))
1904
0
                    || ((msgtype != TCPCLV4_MSGTYPE_SESS_INIT) && (cmp_sess_init <= 0))) {
1905
0
                    expert_add_info(pinfo, item_msg, &ei_tcpclv4_sess_init_missing);
1906
0
                }
1907
0
            }
1908
24
        }
1909
63
    }
1910
1911
63
    if (msgtype_name) {
1912
63
        col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, msgtype_name);
1913
63
    }
1914
1915
63
    try_negotiate(ctx, pinfo);
1916
    // Show negotiation results
1917
63
    if (msgtype == TCPCLV4_MSGTYPE_SESS_INIT) {
1918
0
        if (ctx->convo->sess_negotiated) {
1919
0
            if (ctx->rx_peer->sess_init_seen){
1920
0
                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
0
                proto_item_set_generated(item_nego);
1922
0
            }
1923
0
            {
1924
0
                proto_item *item_nego = proto_tree_add_uint(tree_msg, hf_tcpclv4_negotiate_keepalive, tvb, 0, 0, ctx->convo->sess_keepalive);
1925
0
                proto_item_set_generated(item_nego);
1926
0
            }
1927
0
        }
1928
0
    }
1929
1930
63
    return offset;
1931
67
}
1932
1933
/** Function to extract a message length, or zero if not valid.
1934
 * This will call set_chdr_missing() if valid.
1935
 */
1936
typedef unsigned (*chdr_missing_check)(packet_info *, tvbuff_t *, int offset, tcpcl_dissect_ctx_t *);
1937
1938
/** Inspect a single segment to determine if this looks like a TLS record set.
1939
 */
1940
static unsigned chdr_missing_tls(packet_info *pinfo, tvbuff_t *tvb, int offset,
1941
64
                              tcpcl_dissect_ctx_t *ctx) {
1942
64
    if (ctx->convo->session_tls_start) {
1943
        // already in a TLS context
1944
0
        return 0;
1945
0
    }
1946
1947
    // similar heuristics to is_sslv3_or_tls() from packet-tls.c
1948
64
    if (tvb_captured_length(tvb) < 5) {
1949
1
        return 0;
1950
1
    }
1951
63
    uint8_t rectype = tvb_get_uint8(tvb, offset);
1952
63
    uint16_t recvers = tvb_get_uint16(tvb, offset+1, ENC_BIG_ENDIAN);
1953
63
    uint16_t reclen = tvb_get_uint16(tvb, offset+1+2, ENC_BIG_ENDIAN);
1954
1955
63
    switch(rectype) {
1956
        // These overlap with TCPCLV3_DATA_SEGMENT but have invalid flags
1957
        // They are valid but unallocated v4 message type codes
1958
0
        case SSL_ID_ALERT:
1959
0
        case SSL_ID_HANDSHAKE:
1960
0
        case SSL_ID_APP_DATA:
1961
0
        case SSL_ID_HEARTBEAT:
1962
0
            break;
1963
63
        default:
1964
63
            return 0;
1965
63
    }
1966
0
    if ((recvers & 0xFF00) != 0x0300) {
1967
0
        return 0;
1968
0
    }
1969
0
    if (reclen == 0 || reclen >= TLS_MAX_RECORD_LENGTH + 2048) {
1970
0
        return 0;
1971
0
    }
1972
1973
    // post-STARTTLS
1974
0
    ctx->convo->session_use_tls = true;
1975
0
    ctx->convo->session_tls_start = tcpcl_frame_loc_clone(wmem_file_scope(), ctx->cur_loc);
1976
0
    ssl_starttls_post_ack(tls_handle, pinfo, tcpcl_handle);
1977
1978
0
    return tvb_reported_length(tvb);
1979
1980
0
}
1981
1982
static unsigned chdr_missing_v3(packet_info *pinfo, tvbuff_t *tvb, int offset,
1983
54
                             tcpcl_dissect_ctx_t *ctx) {
1984
54
    unsigned sublen = get_v3_msg_len(pinfo, tvb, offset, ctx);
1985
54
    if (sublen > 0) {
1986
51
        set_chdr_missing(ctx->tx_peer, 3);
1987
51
    }
1988
54
    return sublen;
1989
54
}
1990
1991
static unsigned chdr_missing_v4(packet_info *pinfo, tvbuff_t *tvb, int offset,
1992
64
                             tcpcl_dissect_ctx_t *ctx) {
1993
64
    unsigned sublen = get_v4_msg_len(pinfo, tvb, offset, ctx);
1994
64
    if (sublen > 0) {
1995
10
        set_chdr_missing(ctx->tx_peer, 4);
1996
10
    }
1997
64
    return sublen;
1998
64
}
1999
2000
static const chdr_missing_check chdr_missing_v3first[] = {
2001
    &chdr_missing_tls,
2002
    &chdr_missing_v3,
2003
    &chdr_missing_v4,
2004
    NULL
2005
};
2006
static const chdr_missing_check chdr_missing_v3only[] = {
2007
    &chdr_missing_v3,
2008
    NULL
2009
};
2010
static const chdr_missing_check chdr_missing_v4first[] = {
2011
    &chdr_missing_tls,
2012
    &chdr_missing_v4,
2013
    &chdr_missing_v3,
2014
    NULL
2015
};
2016
static const chdr_missing_check chdr_missing_v4only[] = {
2017
    &chdr_missing_v4,
2018
    NULL
2019
};
2020
2021
4.11k
static unsigned get_message_len(packet_info *pinfo, tvbuff_t *tvb, int ext_offset, void *data _U_) {
2022
4.11k
    tcpcl_dissect_ctx_t *ctx = tcpcl_dissect_ctx_get(tvb, pinfo, ext_offset);
2023
4.11k
    if (!ctx) {
2024
0
        return 0;
2025
0
    }
2026
4.11k
    const unsigned init_offset = ext_offset;
2027
4.11k
    unsigned offset = ext_offset;
2028
2029
4.11k
    if (ctx->is_contact) {
2030
68
        if (tvb_memeql(tvb, offset, magic, sizeof(magic)) != 0) {
2031
            // Optional heuristic dissection of a message
2032
64
            const chdr_missing_check *checks = NULL;
2033
64
            switch (tcpcl_chdr_missing) {
2034
0
                case CHDRMSN_V3FIRST:
2035
0
                    checks = chdr_missing_v3first;
2036
0
                    break;
2037
0
                case CHDRMSN_V3ONLY:
2038
0
                    checks = chdr_missing_v3only;
2039
0
                    break;
2040
64
                case CHDRMSN_V4FIRST:
2041
64
                    checks = chdr_missing_v4first;
2042
64
                    break;
2043
0
                case CHDRMSN_V4ONLY:
2044
0
                    checks = chdr_missing_v4only;
2045
0
                    break;
2046
64
            }
2047
64
            if (checks) {
2048
185
                for (const chdr_missing_check *chk = checks; *chk; ++chk) {
2049
182
                    unsigned sublen = (**chk)(pinfo, tvb, offset, ctx);
2050
182
                    if (sublen > 0) {
2051
61
                        return sublen;
2052
61
                    }
2053
182
                }
2054
                // no match
2055
3
                return 0;
2056
64
            }
2057
0
            else {
2058
                // require the contact header
2059
0
                const unsigned available = tvb_captured_length(tvb) - offset;
2060
0
                if (available < sizeof(magic) + 1) {
2061
0
                    return DESEGMENT_ONE_MORE_SEGMENT;
2062
0
                }
2063
                // sufficient size available but no match
2064
0
                return 0;
2065
0
            }
2066
64
        }
2067
4
        offset += sizeof(magic);
2068
2069
4
        uint8_t version = tvb_get_uint8(tvb, offset);
2070
4
        offset += 1;
2071
4
        if (version == 3) {
2072
1
            offset += 3; // flags + keepalive
2073
1
            uint64_t eid_len;
2074
1
            const unsigned bytecount = tvb_get_sdnv(tvb, offset, &eid_len);
2075
1
            const int len_clamp = get_clamped_length(eid_len, NULL, NULL);
2076
1
            offset += bytecount + len_clamp;
2077
1
        }
2078
3
        else if (version == 4) {
2079
1
            offset += 1; // flags
2080
1
        }
2081
2
        else {
2082
2
            return 0;
2083
2
        }
2084
4
    }
2085
4.04k
    else {
2086
4.04k
        if (ctx->tx_peer->version == 3) {
2087
3.94k
            unsigned sublen = get_v3_msg_len(pinfo, tvb, offset, ctx);
2088
3.94k
            if (sublen == 0) {
2089
81
                return 0;
2090
81
            }
2091
3.86k
            offset += sublen;
2092
3.86k
        }
2093
95
        else if (ctx->tx_peer->version == 4) {
2094
95
            unsigned sublen = get_v4_msg_len(pinfo, tvb, offset, ctx);
2095
95
            if (sublen == 0) {
2096
28
                return 0;
2097
28
            }
2098
67
            offset += sublen;
2099
67
        }
2100
0
        else {
2101
0
            return 0;
2102
0
        }
2103
4.04k
    }
2104
3.93k
    const int needlen = offset - init_offset;
2105
3.93k
    return needlen;
2106
4.11k
}
2107
2108
3.98k
static int dissect_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
2109
3.98k
    int offset = 0;
2110
3.98k
    tcpcl_dissect_ctx_t *ctx = tcpcl_dissect_ctx_get(tvb, pinfo, offset);
2111
3.98k
    if (!ctx) {
2112
0
        return 0;
2113
0
    }
2114
2115
3.98k
    {
2116
3.98k
        const char *proto_name = col_get_text(pinfo->cinfo, COL_PROTOCOL);
2117
3.98k
        if (g_strcmp0(proto_name, proto_name_tcpcl) != 0) {
2118
3.98k
            col_set_str(pinfo->cinfo, COL_PROTOCOL, proto_name_tcpcl);
2119
3.98k
            col_clear(pinfo->cinfo, COL_INFO);
2120
3.98k
        }
2121
3.98k
    }
2122
2123
    // Don't add more than one TCPCL tree item
2124
3.98k
    proto_item *item_tcpcl;
2125
3.98k
    proto_tree *tree_tcpcl;
2126
3.98k
    if (tree && (tree->last_child)
2127
3.98k
            && (PITEM_HFINFO(tree->last_child)->id == proto_tcpcl)) {
2128
2.77k
        item_tcpcl = tree->last_child;
2129
2.77k
        tree_tcpcl = proto_item_get_subtree(item_tcpcl);
2130
2.77k
    }
2131
1.21k
    else {
2132
1.21k
        item_tcpcl = proto_tree_add_item(tree, proto_tcpcl, tvb, 0, 0, ENC_NA);
2133
1.21k
        tree_tcpcl = proto_item_add_subtree(item_tcpcl, ett_proto_tcpcl);
2134
1.21k
    }
2135
2136
3.98k
    if (ctx->tx_peer->chdr_missing) {
2137
3.95k
        expert_add_info(pinfo, item_tcpcl, &ei_chdr_missing);
2138
3.95k
    }
2139
3.98k
    if (ctx->is_contact) {
2140
2
        col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "Contact Header");
2141
2142
2
        proto_item *item_chdr = proto_tree_add_item(tree_tcpcl, hf_chdr_tree, tvb, offset, -1, ENC_NA);
2143
2
        proto_tree *tree_chdr = proto_item_add_subtree(item_chdr, ett_chdr);
2144
2145
2
        proto_item *item_magic = proto_tree_add_item(tree_chdr, hf_chdr_magic, tvb, offset, sizeof(magic), ENC_SEP_NONE);
2146
2
        if (tvb_memeql(tvb, offset, magic, sizeof(magic)) != 0) {
2147
0
            expert_add_info(pinfo, item_magic, &ei_invalid_magic);
2148
0
            return 0;
2149
0
        }
2150
2
        offset += sizeof(magic);
2151
2152
2
        ctx->tx_peer->version = tvb_get_uint8(tvb, offset);
2153
2
        proto_item *item_version = proto_tree_add_uint(tree_chdr, hf_chdr_version, tvb, offset, 1, ctx->tx_peer->version);
2154
2
        offset += 1;
2155
2156
        // Mark or check version match
2157
2
        if (!ctx->convo->version) {
2158
2
            ctx->convo->version = wmem_new(wmem_file_scope(), uint8_t);
2159
2
            *(ctx->convo->version) = ctx->tx_peer->version;
2160
2
        }
2161
0
        else if (*(ctx->convo->version) != ctx->tx_peer->version) {
2162
0
            expert_add_info(pinfo, item_version, &ei_mismatch_version);
2163
0
        }
2164
2165
2
        if ((ctx->tx_peer->version < 3) || (ctx->tx_peer->version > 4)) {
2166
0
            expert_add_info(pinfo, item_version, &ei_invalid_version);
2167
0
            return offset;
2168
0
        }
2169
2170
2
        if (ctx->tx_peer->version == 3) {
2171
            /* Subtree to expand the bits in the Contact Header Flags */
2172
1
            proto_tree_add_bitmask(tree_chdr, tvb, offset, hf_tcpclv3_chdr_flags, ett_tcpclv3_chdr_flags, v3_chdr_flags, ENC_BIG_ENDIAN);
2173
1
            offset++;
2174
2175
1
            proto_tree_add_item(tree_chdr, hf_tcpclv3_chdr_keep_alive, tvb, offset, 2, ENC_BIG_ENDIAN);
2176
1
            offset += 2;
2177
2178
            /*
2179
             * New format Contact header has length field followed by EID.
2180
             */
2181
1
            uint64_t eid_length;
2182
1
            int sdnv_length;
2183
1
            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
1
            if (sdnv_length == 0) {
2185
0
                expert_add_info(pinfo, sub_item, &ei_tcpclv3_eid_length);
2186
0
                return 0;
2187
0
            }
2188
1
            offset += sdnv_length;
2189
1
            const int eid_len_clamp = get_clamped_length(eid_length, pinfo, sub_item);
2190
2191
1
            proto_tree_add_item(tree_chdr, hf_tcpclv3_chdr_local_eid, tvb, offset, eid_len_clamp, ENC_NA|ENC_ASCII);
2192
1
            offset += eid_len_clamp;
2193
2194
            // assumed parameters
2195
1
            ctx->tx_peer->segment_mru = UINT64_MAX;
2196
1
            ctx->tx_peer->transfer_mru = UINT64_MAX;
2197
1
        }
2198
1
        else if (ctx->tx_peer->version == 4) {
2199
1
            uint8_t flags = tvb_get_uint8(tvb, offset);
2200
1
            proto_tree_add_bitmask(tree_chdr, tvb, offset, hf_tcpclv4_chdr_flags, ett_tcpclv4_chdr_flags, v4_chdr_flags, ENC_BIG_ENDIAN);
2201
1
            offset += 1;
2202
2203
1
            ctx->tx_peer->can_tls = (flags & TCPCLV4_CONTACT_FLAG_CANTLS);
2204
1
        }
2205
2206
2
        proto_item_set_len(item_chdr, offset);
2207
2208
2
        if (ctx->tx_peer->chdr_seen) {
2209
0
            if (tcpcl_analyze_sequence) {
2210
0
                if (!tcpcl_frame_loc_equal(ctx->tx_peer->chdr_seen, ctx->cur_loc)) {
2211
0
                    expert_add_info(pinfo, item_chdr, &ei_chdr_duplicate);
2212
0
                }
2213
0
            }
2214
0
        }
2215
2
        else {
2216
2
            ctx->tx_peer->chdr_seen = tcpcl_frame_loc_clone(wmem_file_scope(), ctx->cur_loc);
2217
2
        }
2218
2219
2
        try_negotiate(ctx, pinfo);
2220
        // Show negotiation results
2221
2
        if (ctx->convo->contact_negotiated) {
2222
0
            if (ctx->rx_peer->chdr_seen) {
2223
0
                proto_item *item_nego = proto_tree_add_uint(tree_chdr, hf_chdr_related, tvb, 0, 0, ctx->rx_peer->chdr_seen->frame_num);
2224
0
                proto_item_set_generated(item_nego);
2225
0
            }
2226
0
            if (ctx->tx_peer->version == 4) {
2227
0
                proto_item *item_nego = proto_tree_add_boolean(tree_chdr, hf_tcpclv4_negotiate_use_tls, tvb, 0, 0, ctx->convo->session_use_tls);
2228
0
                proto_item_set_generated(item_nego);
2229
0
            }
2230
0
        }
2231
2
    }
2232
3.98k
    else {
2233
3.98k
        if (ctx->tx_peer->version == 3) {
2234
3.91k
            offset += dissect_v3_msg(tvb, pinfo, tree_tcpcl, ctx);
2235
3.91k
        }
2236
67
        else if (ctx->tx_peer->version == 4) {
2237
67
            offset += dissect_v4_msg(tvb, pinfo, tree_tcpcl, ctx);
2238
67
        }
2239
3.98k
    }
2240
2241
3.98k
    const int item_len = proto_item_get_len(item_tcpcl);
2242
3.98k
    bool is_new_item_tcpcl = (item_len <= 0);
2243
3.98k
    if (is_new_item_tcpcl) {
2244
787
        proto_item_set_len(item_tcpcl, offset);
2245
787
        proto_item_append_text(item_tcpcl, " Version %d", ctx->tx_peer->version);
2246
787
    }
2247
3.19k
    else {
2248
3.19k
        proto_item_set_len(item_tcpcl, item_len + offset);
2249
3.19k
    }
2250
2251
3.98k
    if (ctx->xferload) {
2252
184
        col_append_str(pinfo->cinfo, COL_INFO, " [Bundle]");
2253
2254
184
        if (tcpcl_decode_bundle) {
2255
184
            if (bundle_handle) {
2256
184
                call_dissector(
2257
184
                    bundle_handle,
2258
184
                    ctx->xferload,
2259
184
                    pinfo,
2260
184
                    tree
2261
184
                );
2262
184
            }
2263
184
        }
2264
184
    }
2265
2266
3.98k
    return offset;
2267
3.98k
}
2268
2269
static int
2270
dissect_tcpcl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
2271
151
{
2272
    /* Retrieve information from conversation, or add it if it isn't
2273
     * there yet */
2274
151
    conversation_t *convo = find_or_create_conversation(pinfo);
2275
151
    tcpcl_conversation_t *tcpcl_convo = (tcpcl_conversation_t *)conversation_get_proto_data(convo, proto_tcpcl);
2276
151
    if (!tcpcl_convo) {
2277
67
        tcpcl_convo = tcpcl_conversation_new();
2278
67
        conversation_add_proto_data(convo, proto_tcpcl, tcpcl_convo);
2279
        // Assume the first source (i.e. TCP initiator) is the active node
2280
67
        copy_address_wmem(wmem_file_scope(), &(tcpcl_convo->active->addr), &(pinfo->src));
2281
67
        tcpcl_convo->active->port = pinfo->srcport;
2282
67
        copy_address_wmem(wmem_file_scope(), &(tcpcl_convo->passive->addr), &(pinfo->dst));
2283
67
        tcpcl_convo->passive->port = pinfo->destport;
2284
67
    }
2285
2286
151
    tcp_dissect_pdus(tvb, pinfo, tree, true, 1, get_message_len, dissect_message, NULL);
2287
2288
151
    const unsigned buflen = tvb_captured_length(tvb);
2289
151
    return buflen;
2290
151
}
2291
2292
static bool
2293
dissect_tcpcl_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2294
1.90k
{
2295
1.90k
    if (tvb_reported_length(tvb) < minimum_chdr_size) {
2296
115
        return false;
2297
115
    }
2298
1.79k
    if (tvb_memeql(tvb, 0, magic, sizeof(magic)) != 0) {
2299
1.79k
        return false;
2300
1.79k
    }
2301
2302
    // treat the rest of the connection as TCPCL
2303
4
    conversation_t *convo = find_or_create_conversation(pinfo);
2304
4
    conversation_set_dissector(convo, tcpcl_handle);
2305
2306
4
    dissect_tcpcl(tvb, pinfo, tree, data);
2307
4
    return true;
2308
1.79k
}
2309
2310
0
static int dissect_xferext_transferlen(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_) {
2311
0
    int offset = 0;
2312
0
    tcpcl_dissect_ctx_t *ctx = tcpcl_dissect_ctx_get(tvb, pinfo, offset);
2313
0
    if (!ctx) {
2314
0
        return 0;
2315
0
    }
2316
2317
0
    uint64_t total_len = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
2318
0
    proto_item *item_len = proto_tree_add_uint64(tree, hf_tcpclv4_xferext_transferlen_total_len, tvb, offset, 8, total_len);
2319
0
    offset += 8;
2320
0
    if (total_len > ctx->rx_peer->transfer_mru) {
2321
0
        expert_add_info(pinfo, item_len, &ei_tcpclv4_xferload_over_xfer_mru);
2322
0
    }
2323
2324
0
    if (tcpcl_analyze_sequence) {
2325
0
        uint64_t *xfer_id = wmem_map_lookup(ctx->tx_peer->frame_loc_to_transfer, ctx->cur_loc);
2326
0
        if (xfer_id) {
2327
0
            tcpcl_transfer_t *xfer = get_or_create_transfer_t(ctx->tx_peer->transfers, *xfer_id);
2328
0
            xfer->total_length = wmem_new(wmem_file_scope(), uint64_t);
2329
0
            *(xfer->total_length) = total_len;
2330
0
        }
2331
0
    }
2332
2333
0
    return offset;
2334
0
}
2335
2336
0
static int dissect_othername_bundleeid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
2337
0
    int offset = 0;
2338
0
    asn1_ctx_t actx;
2339
0
    asn1_ctx_init(&actx, ASN1_ENC_BER, true, pinfo);
2340
0
    offset += dissect_ber_restricted_string(
2341
0
        false, BER_UNI_TAG_IA5String,
2342
0
        &actx, tree, tvb, offset, hf_othername_bundleeid, NULL
2343
0
    );
2344
0
    return offset;
2345
0
}
2346
2347
/// Re-initialize after a configuration change
2348
14
static void reinit_tcpcl(void) {
2349
14
}
2350
2351
void
2352
proto_register_tcpcl(void)
2353
14
{
2354
14
    expert_module_t *expert_tcpcl;
2355
2356
14
    proto_tcpcl = proto_register_protocol(
2357
14
        "DTN TCP Convergence Layer Protocol",
2358
14
        "TCPCL",
2359
14
        "tcpcl"
2360
14
    );
2361
2362
14
    proto_tcpcl_exts = proto_register_protocol_in_name_only(
2363
14
        "TCPCL Extension Subdissectors",
2364
14
        "TCPCL Extension Subdissectors",
2365
14
        "tcpcl_exts",
2366
14
        proto_tcpcl,
2367
14
        FT_PROTOCOL
2368
14
    );
2369
2370
14
    proto_register_field_array(proto_tcpcl, hf_tcpcl, array_length(hf_tcpcl));
2371
14
    proto_register_subtree_array(ett, array_length(ett));
2372
14
    expert_tcpcl = expert_register_protocol(proto_tcpcl);
2373
14
    expert_register_field_array(expert_tcpcl, ei_tcpcl, array_length(ei_tcpcl));
2374
2375
14
    tcpcl_handle = register_dissector("tcpcl", dissect_tcpcl, proto_tcpcl);
2376
14
    sess_ext_dissectors = register_dissector_table("tcpcl.v4.sess_ext", "TCPCLv4 Session Extension", proto_tcpcl, FT_UINT16, BASE_HEX);
2377
14
    xfer_ext_dissectors = register_dissector_table("tcpcl.v4.xfer_ext", "TCPCLv4 Transfer Extension", proto_tcpcl, FT_UINT16, BASE_HEX);
2378
2379
14
    module_t *module_tcpcl = prefs_register_protocol(proto_tcpcl, reinit_tcpcl);
2380
14
    prefs_register_enum_preference(
2381
14
        module_tcpcl,
2382
14
        "allow_chdr_missing",
2383
14
        "Allow missing Contact Header",
2384
14
        "Whether the TCPCL dissector should use heuristic "
2385
14
        "dissection of messages in the absence of a Contact Header "
2386
14
        "(if the capture misses the start of session).",
2387
14
        &tcpcl_chdr_missing,
2388
14
        chdr_missing_choices,
2389
14
        false
2390
14
    );
2391
14
    prefs_register_bool_preference(
2392
14
        module_tcpcl,
2393
14
        "analyze_sequence",
2394
14
        "Analyze message sequences",
2395
14
        "Whether the TCPCL dissector should analyze the sequencing of "
2396
14
        "the messages within each session.",
2397
14
        &tcpcl_analyze_sequence
2398
14
    );
2399
14
    prefs_register_bool_preference(
2400
14
        module_tcpcl,
2401
14
        "desegment_transfer",
2402
14
        "Reassemble the segments of each transfer",
2403
14
        "Whether the TCPCL dissector should combine the sequential segments "
2404
14
        "of a transfer into the full bundle being transferred."
2405
14
        "To use this option, you must also enable "
2406
14
        "\"Allow subdissectors to reassemble TCP streams\" "
2407
14
        "in the TCP protocol settings.",
2408
14
        &tcpcl_desegment_transfer
2409
14
    );
2410
14
    prefs_register_bool_preference(
2411
14
        module_tcpcl,
2412
14
        "decode_bundle",
2413
14
        "Decode bundle data",
2414
14
        "If enabled, the transfer bundle will be decoded.",
2415
14
        &tcpcl_decode_bundle
2416
14
    );
2417
2418
14
    reassembly_table_register(
2419
14
        &xfer_reassembly_table,
2420
14
        &xfer_reassembly_table_functions
2421
14
    );
2422
2423
14
}
2424
2425
void
2426
proto_reg_handoff_tcpcl(void)
2427
14
{
2428
14
    tls_handle = find_dissector_add_dependency("tls", proto_tcpcl);
2429
14
    bundle_handle = find_dissector("bundle");
2430
2431
14
    dissector_add_uint_with_preference("tcp.port", BUNDLE_PORT, tcpcl_handle);
2432
14
    heur_dissector_add("tcp", dissect_tcpcl_heur, "TCPCL over TCP", "tcpcl_tcp", proto_tcpcl, HEURISTIC_ENABLE);
2433
2434
    /* Packaged extensions */
2435
14
    {
2436
14
        dissector_handle_t dis_h = create_dissector_handle_with_name_and_description(dissect_xferext_transferlen, proto_tcpcl_exts, NULL, "Transfer Length");
2437
14
        dissector_add_uint("tcpcl.v4.xfer_ext", TCPCLV4_XFEREXT_TRANSFER_LEN, dis_h);
2438
14
    }
2439
2440
14
    register_ber_oid_dissector("1.3.6.1.5.5.7.3.35", NULL, proto_tcpcl_exts, "id-kp-bundleSecurity");
2441
14
    register_ber_oid_dissector("1.3.6.1.5.5.7.8.11", dissect_othername_bundleeid, proto_tcpcl_exts, "id-on-bundleEID");
2442
2443
14
    reinit_tcpcl();
2444
14
}
2445
2446
/*
2447
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
2448
 *
2449
 * Local variables:
2450
 * c-basic-offset: 4
2451
 * tab-width: 8
2452
 * indent-tabs-mode: nil
2453
 * End:
2454
 *
2455
 * vi: set shiftwidth=4 tabstop=8 expandtab:
2456
 * :indentSize=4:tabSize=8:noTabs=true:
2457
 */