summaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-tcp.h
blob: 1e1097a3e39ef9681e8f08a6f2e4717996b983ef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
/* packet-tcp.h
 *
 * Wireshark - Network traffic analyzer
 * By Gerald Combs <gerald@wireshark.org>
 * Copyright 1998 Gerald Combs
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

#ifndef __PACKET_TCP_H__
#define __PACKET_TCP_H__

#include "ws_symbol_export.h"

#include <epan/conversation.h>
#include <epan/reassemble.h>
#include <epan/wmem_scopes.h>

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/* TCP flags */
#define TH_FIN  0x0001
#define TH_SYN  0x0002
#define TH_RST  0x0004
#define TH_PUSH 0x0008
#define TH_ACK  0x0010
#define TH_URG  0x0020
#define TH_ECE  0x0040
#define TH_CWR  0x0080
#define TH_AE   0x0100
#define TH_RES  0x0E00 /* 3 reserved bits */
#define TH_MASK 0x0FFF

#define IS_TH_FIN(x) (x & TH_FIN)
#define IS_TH_URG(x) (x & TH_URG)

/* Idea for gt: either x > y, or y is much bigger (assume wrap) */
#define GT_SEQ(x, y) ((int32_t)((y) - (x)) < 0)
#define LT_SEQ(x, y) ((int32_t)((x) - (y)) < 0)
#define GE_SEQ(x, y) ((int32_t)((y) - (x)) <= 0)
#define LE_SEQ(x, y) ((int32_t)((x) - (y)) <= 0)
#define EQ_SEQ(x, y) (x) == (y)

/* mh as in mptcp header */
struct mptcpheader {

	bool mh_mpc;         /* true if seen an mp_capable option */
	bool mh_join;        /* true if seen an mp_join option */
	bool mh_dss;         /* true if seen a dss */
	bool mh_add;         /* true if seen an MP_ADD */
	bool mh_remove;      /* true if seen an MP_REMOVE */
	bool mh_prio;        /* true if seen an MP_PRIO */
	bool mh_fail;        /* true if seen an MP_FAIL */
	bool mh_fastclose;   /* true if seen a fastclose */
	bool mh_tcprst;      /* true if seen a MP_TCPRST */

	uint8_t mh_capable_flags; /* to get hmac version for instance */
	uint8_t mh_dss_flags; /* data sequence signal flag */
	uint32_t mh_dss_ssn; /* DSS Subflow Sequence Number */
	uint64_t mh_dss_rawdsn; /* DSS Data Sequence Number */
	uint64_t mh_dss_rawack; /* DSS raw data ack */
	uint16_t mh_dss_length;  /* mapping/DSS length */

	uint64_t mh_key; /* Sender key in MP_CAPABLE */
	uint32_t mh_token; /* seen in MP_JOIN. Should be a hash of the initial key */

	uint32_t mh_stream; /* this stream index field is included to help differentiate when address/port pairs are reused */

	/* Data Sequence Number of the current segment. It needs to be computed from previous mappings
	 * and as such is not necessarily set
	 */
	uint64_t mh_rawdsn64;
	/* DSN formatted according to  the wireshark MPTCP options */
	uint64_t mh_dsn;
};

/* the tcp header structure, passed to tap listeners */
typedef struct tcpheader {
	uint32_t th_rawseq;  /* raw value */
	uint32_t th_seq;     /* raw or relative value depending on tcp_relative_seq */

	uint32_t th_rawack;  /* raw value */
	uint32_t th_ack;     /* raw or relative value depending on tcp_relative_seq */
	bool th_have_seglen;	/* true if th_seglen is valid */
	uint32_t th_seglen;  /* in bytes */
	uint32_t th_win;   /* make it 32 bits so we can handle some scaling */
	uint16_t th_sport;
	uint16_t th_dport;
	uint8_t th_hlen;
	bool th_use_ace;
	uint16_t th_flags;
	uint32_t th_stream; /* this stream index field is included to help differentiate when address/port pairs are reused */
	address ip_src;
	address ip_dst;

	/* This is the absolute maximum we could find in TCP options (RFC2018, section 3) */
	#define MAX_TCP_SACK_RANGES 4
	uint8_t num_sack_ranges;
	uint32_t sack_left_edge[MAX_TCP_SACK_RANGES];
	uint32_t sack_right_edge[MAX_TCP_SACK_RANGES];

	/* header for TCP option Multipath Operation */
	struct mptcpheader *th_mptcp;
} tcp_info_t;

/*
 * Private data passed from the TCP dissector to subdissectors.
 * NOTE: This structure is used by Export PDU functionality so
 * make sure that handling is also updated if this structure
 * changes!
 */
struct tcpinfo {
	uint32_t seq;             /* Sequence number of first byte in the data */
	uint32_t nxtseq;          /* Sequence number of first byte after data */
	uint32_t lastackseq;      /* Sequence number of last ack */
	bool    is_reassembled;   /* This is reassembled data. */
	uint16_t flags;           /* TCP flags */
	uint16_t urgent_pointer;  /* Urgent pointer value for the current packet. */
	uint32_t stream;          /* Stream id passed to export PDU */
};

/*
 * Loop for dissecting PDUs within a TCP stream; assumes that a PDU
 * consists of a fixed-length chunk of data that contains enough information
 * to determine the length of the PDU, followed by rest of the PDU.
 *
 * The first three arguments are the arguments passed to the dissector
 * that calls this routine.
 *
 * "proto_desegment" is the dissector's flag controlling whether it should
 * desegment PDUs that cross TCP segment boundaries.
 *
 * "fixed_len" is the length of the fixed-length part of the PDU.
 *
 * "get_pdu_len()" is a routine called to get the length of the PDU from
 * the fixed-length part of the PDU; it's passed "pinfo", "tvb", "offset" and
 * "dissector_data".
 *
 * "dissect_pdu()" is the routine to dissect a PDU.
 */
WS_DLL_PUBLIC void
tcp_dissect_pdus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
		 bool proto_desegment, unsigned fixed_len,
		 unsigned (*get_pdu_len)(packet_info *, tvbuff_t *, int, void*),
		 dissector_t dissect_pdu, void* dissector_data);

extern const reassembly_table_functions
tcp_reassembly_table_functions;

extern struct tcp_multisegment_pdu *
pdu_store_sequencenumber_of_next_pdu(packet_info *pinfo, uint32_t seq, uint32_t nxtpdu, wmem_tree_t *multisegment_pdus);

typedef struct _tcp_unacked_t {
	struct _tcp_unacked_t *next;
	uint32_t frame;
	uint32_t	seq;
	uint32_t	nextseq;
	nstime_t ts;
} tcp_unacked_t;

struct tcp_acked {
	uint32_t frame_acked;
	nstime_t ts;

	uint32_t rto_frame;
	nstime_t rto_ts;	/* Time since previous packet for
				   retransmissions. */
	uint16_t flags; /* see TCP_A_* in packet-tcp.c */
	uint32_t dupack_num;	/* dup ack number */
	uint32_t dupack_frame;	/* dup ack to frame # */
	uint32_t bytes_in_flight; /* number of bytes in flight */
	uint32_t push_bytes_sent; /* bytes since the last PSH flag */

	uint32_t new_data_seq; /* For segments with old data,
				 where new data starts */
	bool partial_ack; /* true when acknowledging data
				 and not a full segment */
};

/* One instance of this structure is created for each pdu that spans across
 * multiple tcp segments.
 */
struct tcp_multisegment_pdu {
	uint32_t seq;
	uint32_t nxtpdu;
	uint32_t first_frame;            /* The frame where this MSP was created (used as key in reassembly tables). */
	uint32_t last_frame;
	nstime_t last_frame_time;
	uint32_t first_frame_with_seq;   /* The frame that contains the first frame that matches 'seq'
					   (same as 'first_frame', larger than 'first_frame' for OoO segments) */
	uint32_t flags;
#define MSP_FLAGS_REASSEMBLE_ENTIRE_SEGMENT	0x00000001
/* Whether this MSP is finished and no more segments can be added. */
#define MSP_FLAGS_GOT_ALL_SEGMENTS		0x00000002
/* Whether the first segment of this MSP was not yet seen. */
#define MSP_FLAGS_MISSING_FIRST_SEGMENT		0x00000004
};


/* Represents the MPTCP DSS option mapping part
 It allows to map relative subflow sequence number (ssn) to global MPTCP sequence numbers
 under their 64 bits form
*/
typedef struct _mptcp_dss_mapping_t {

/* In DSS, SSN are enumerated with relative seq_nb, i.e. starting from 0 */

	uint32_t ssn_low;
	uint32_t ssn_high;

/* Ideally the dsn should always be registered with the extended version
 * but it may not be possible if we don't know the 32 MSB of the base_dsn
 */
	bool extended_dsn; /* true if MPTCP_DSS_FLAG_DATA_8BYTES */

	uint64_t rawdsn;    /* matches the low member of range
                    should be converted to the 64 bits version before being registered
                */
/* to check if mapping was sent before or after packet */
uint32_t frame;
} mptcp_dss_mapping_t;


/* Structure used in mptcp meta member 'dsn_map'
 */
typedef struct _mptcp_dsn2packet_mapping_t {
	uint32_t frame;                  /* packet to look into PINFO_FD_NUM */
	struct tcp_analysis* subflow;   /* in order to get statistics */
} mptcp_dsn2packet_mapping_t;


/* Should basically look like a_tcp_flow_t but for mptcp with 64bit sequence number.
The meta is specific to a direction of the communication and aggregates information of
all the subflows
*/
typedef struct _mptcp_meta_flow_t {

	uint8_t static_flags;	/* remember which fields are set */

	/* flags exchanged between hosts during 3WHS. Gives checksum/extensibility/hmac information */
	uint8_t flags;
	uint64_t base_dsn;	/* first data seq number (used by relative sequence numbers) seen. */
	uint64_t nextseq;	/* highest seen nextseq */
	uint64_t dfin;		/* data fin */

	uint8_t version;		/* negotiated mptcp version */

	uint64_t key;		/* if it was set */

	/* expected token sha1 digest of keys, truncated to 32 most significant bits
	 derived from key. Stored to speed up subflow/MPTCP connection mapping */
	uint32_t token;

	uint32_t nextseqframe;	/* frame number for segment with highest sequence number */

	/* highest seen continuous seq number (without hole in the stream)  */
	uint64_t maxseqtobeacked;

	uint64_t fin;		/* frame number of the final dataFIN */

	/* first addresses registered */
	address ip_src;
	address ip_dst;
	uint32_t sport;
	uint32_t dport;
} mptcp_meta_flow_t;

/* MPTCP data specific to this subflow direction */
struct mptcp_subflow {
	uint8_t static_flags; /* flags stating which of the flow */
	uint32_t nonce;       /* used only for MP_JOIN */
	uint8_t address_id;   /* sent during an MP_JOIN */


	/* map DSN to packets
	 * Used when looking for reinjections across subflows
	 */
	wmem_itree_t *dsn2packet_map;

	/* Map SSN to a DSS mappings
	 * a DSS can map DSN to SSNs possibily over several packets,
	 * hence some packets may have been mapped by previous DSS,
	 * whence the necessity to be able to look for SSN -> DSN */
	wmem_itree_t *ssn2dsn_mappings;
	/* meta flow to which it is attached. Helps setting forward and backward meta flow */
	mptcp_meta_flow_t *meta;
};


typedef enum {
	MPTCP_HMAC_NOT_SET = 0,
	/* this is either SHA1 for MPTCP v0 or sha256 for MPTCP v1 */
	MPTCP_HMAC_SHA = 1,
	MPTCP_HMAC_LAST
} mptcp_hmac_algorithm_t;


#define MPTCP_CAPABLE_CRYPTO_MASK           0x3F

#define MPTCP_CHECKSUM_MASK                 0x80

/* Information in a flow that is only used when tcp_analyze_seq preference
 * is enabled, so save the memory when it isn't
 */
typedef struct tcp_analyze_seq_flow_info_t {
	tcp_unacked_t *segments;/* List of segments for which we haven't seen an ACK */
	uint16_t segment_count;	/* How many unacked segments we're currently storing */
	uint32_t lastack;	/* Last seen ack for the reverse flow */
	nstime_t lastacktime;	/* Time of the last ack packet */
	uint32_t lastnondupack;	/* frame number of last seen non dupack */
	uint32_t dupacknum;	/* dupack number */
	uint32_t nextseq;	/* highest seen nextseq */
	uint32_t maxseqtobeacked;/* highest seen continuous seq number (without hole in the stream) from the fwd party,
				 * this is the maximum seq number that can be acked by the rev party in normal case.
				 * If the rev party sends an ACK beyond this seq number it indicates TCP_A_ACK_LOST_PACKET condition */
	uint32_t nextseqframe;	/* frame number for segment with highest
				 * sequence number
				 */
	nstime_t nextseqtime;	/* Time of the nextseq packet so we can
				 * distinguish between retransmission,
				 * fast retransmissions and outoforder
				 */

	uint8_t lastacklen;     /* length of the last fwd ACK packet - 0 means pure ACK */

	/*
	 * Handling of SACK blocks
	 * Copied from tcpheader
	 */
	uint8_t num_sack_ranges;
	uint32_t sack_left_edge[MAX_TCP_SACK_RANGES];
	uint32_t sack_right_edge[MAX_TCP_SACK_RANGES];

} tcp_analyze_seq_flow_info_t;

	/* Process info, currently discovered via IPFIX */
typedef struct tcp_process_info_t {
	uint32_t process_uid;	/* UID of local process */
	uint32_t process_pid;	/* PID of local process */
	char   *username;		/* Username of the local process */
	char   *command;		/* Local process name + path + args */

} tcp_process_info_t;

typedef struct _tcp_flow_t {
	uint8_t static_flags; /* true if base seq set */
	uint32_t base_seq;	/* base seq number (used by relative sequence numbers)*/
#define TCP_MAX_UNACKED_SEGMENTS 10000 /* The most unacked segments we'll store */
	uint32_t fin;		/* frame number of the final FIN */
	uint32_t window;		/* last seen window */
	int16_t	win_scale;	/* -1 is we don't know, -2 is window scaling is not used */
	int16_t scps_capable;   /* flow advertised scps capabilities */
	uint16_t maxsizeacked;   /* 0 if not yet known */
	bool valid_bif;     /* if lost pkts, disable BiF until ACK is recvd */
	uint32_t push_bytes_sent; /* bytes since the last PSH flag */
	bool push_set_last; /* tracking last time PSH flag was set */
	uint8_t mp_operations; /* tracking of the MPTCP operations */
	bool is_first_ack;  /* indicates if this is the first ACK */
	bool closing_initiator; /* tracking who is responsible of the connection end */

	tcp_analyze_seq_flow_info_t* tcp_analyze_seq_info;

/* This tcp flow/session contains only one single PDU and should
 * be reassembled until the final FIN segment.
 */
#define TCP_FLOW_REASSEMBLE_UNTIL_FIN	0x0001
	uint16_t flags;

	/* see TCP_A_* in packet-tcp.c */
	uint32_t lastsegmentflags;

	/* The next (largest) sequence number after all segments seen so far.
	 * Valid only on the first pass and used to handle out-of-order segments
	 * during reassembly. */
	uint32_t maxnextseq;

	/* The number of data flows seen in that direction */
	uint16_t flow_count;

	/* This tree is indexed by sequence number and keeps track of all
	 * all pdus spanning multiple segments for this flow.
	 */
	wmem_tree_t *multisegment_pdus;

	/* A sorted list of pending out-of-order segments. */
	wmem_list_t *ooo_segments;

	/* Process info, currently discovered via IPFIX */
	tcp_process_info_t* process_info;

	/* MPTCP subflow intel */
	struct mptcp_subflow *mptcp_subflow;
} tcp_flow_t;

/* Stores common information between both hosts of the MPTCP connection*/
struct mptcp_analysis {

	uint16_t mp_flags; /* MPTCP meta analysis related, see MPTCP_META_* in packet-tcp.c */

	/*
	 * For other subflows, they link the meta via mptcp_subflow_t::meta_flow
	 * according to the validity of the token.
	 */
	mptcp_meta_flow_t meta_flow[2];

	uint32_t stream; /* Keep track of unique mptcp stream (per MP_CAPABLE handshake) */
	uint8_t hmac_algo;  /* hmac decided after negotiation */
	wmem_list_t* subflows;	/* List of subflows (tcp_analysis) */

	/* identifier of the tcp stream that saw the initial 3WHS with MP_CAPABLE option */
	struct tcp_analysis *master;

	/* Keep track of the last TCP operations seen in order to avoid false DUP ACKs */
	uint8_t mp_operations;
};

struct tcp_analysis {
	/* These two structs are managed based on comparing the source
	 * and destination addresses and, if they're equal, comparing
	 * the source and destination ports.
	 *
	 * If the source is greater than the destination, then stuff
	 * sent from src is in ual1.
	 *
	 * If the source is less than the destination, then stuff
	 * sent from src is in ual2.
	 *
	 * XXX - if the addresses and ports are equal, we don't guarantee
	 * the behavior.
	 */
	tcp_flow_t	flow1;
	tcp_flow_t	flow2;

	/* These pointers are set by get_tcp_conversation_data()
	 * fwd point in the same direction as the current packet
	 * and rev in the reverse direction
	 */
	tcp_flow_t	*fwd;
	tcp_flow_t	*rev;

	/* This pointer is NULL   or points to a tcp_acked struct if this
	 * packet has "interesting" properties such as being a KeepAlive or
	 * similar
	 */
	struct tcp_acked *ta;
	/* This structure contains a tree containing all the various ta's
	 * keyed by frame number.
	 */
	wmem_tree_t	*acked_table;

	/* Remember the timestamp of the first frame seen in this tcp
	 * conversation to be able to calculate a relative time compared
	 * to the start of this conversation
	 */
	nstime_t	ts_first;

        /* Remember the timestamp of the most recent SYN in this conversation in
         * order to calculate the first_rtt below. Not necessarily ts_first, if
         * the SYN is retransmitted. */
	nstime_t	ts_mru_syn;

        /* If we have the handshake, remember the RTT between the initial SYN
         * and ACK for use detecting out-of-order segments. */
	nstime_t	ts_first_rtt;

	/* Remember the timestamp of the frame that was last seen in this
	 * tcp conversation to be able to calculate a delta time compared
	 * to previous frame in this conversation
	 */
	nstime_t	ts_prev;

	/* Keep track of tcp stream numbers instead of using the conversation
	 * index (as how it was done before). This prevents gaps in the
	 * stream index numbering
	 */
	uint32_t        stream;

	/* Keep track of packet number within the TCP stream */
	uint32_t        pnum;

	/* Remembers the server port on the SYN (or SYN|ACK) packet to
	 * help determine which dissector to call
	 */
	uint16_t server_port;
	/* Set when the client sends a SYN with data and the cookie in the Fast Open
	 * option.
	 */
	uint8_t tfo_syn_data : 1;

	/* Remembers which side is currently sending data. */
	int8_t flow_direction : 2;

	/* allocated only when mptcp enabled
	 * several tcp_analysis may refer to the same mptcp_analysis
	 * can exist without any meta
	 */
	struct mptcp_analysis* mptcp_analysis;

	/* Track the TCP conversation completeness, as the capture might
	 * contain all parts of a TCP flow (establishment, data, clearing) or
	 * just some parts if we jumped on the bandwagon of an already established
	 * connection or left before it was terminated explicitly
	 */
	uint8_t         conversation_completeness;

	/* Stores the value as a String to be displayed in the appropriate field */
	char            *conversation_completeness_str;

	/* Track AccECN support */
	bool had_acc_ecn_setup_syn;
	bool had_acc_ecn_setup_syn_ack;
	bool had_acc_ecn_option;
};

/* Structure that keeps per packet data. First used to be able
 * to calculate the time_delta from the last seen frame in this
 * TCP conversation. Can be extended for future use.
 */
struct tcp_per_packet_data_t {
	nstime_t	ts_del;
	uint32_t        pnum;
	uint8_t		tcp_snd_manual_analysis;
};

/* Structure that keeps per packet data. Some operations are cpu-intensive and are
 * best cached into this structure
 */
typedef struct mptcp_per_packet_data_t_ {

	/* Mapping that covers this packet content */
	mptcp_dss_mapping_t *mapping;

} mptcp_per_packet_data_t;


WS_DLL_PUBLIC void dissect_tcp_payload(tvbuff_t *tvb, packet_info *pinfo, int offset,
				uint32_t seq, uint32_t nxtseq, uint32_t sport,
				uint32_t dport, proto_tree *tree,
				proto_tree *tcp_tree,
				struct tcp_analysis *tcpd, struct tcpinfo *tcpinfo);

WS_DLL_PUBLIC struct tcp_analysis *get_tcp_conversation_data(conversation_t *conv,
                                packet_info *pinfo);

/** Same as get_tcp_conversation_data(), without updating any data at all. Thus,
 *  it really identifies the conversation data and doesn't do anything with it.
 *
 */
WS_DLL_PUBLIC struct tcp_analysis *get_tcp_conversation_data_idempotent(conversation_t *conv);

WS_DLL_PUBLIC bool decode_tcp_ports(tvbuff_t *, int, packet_info *, proto_tree *, int, int, struct tcp_analysis *, struct tcpinfo *);

/** Associate process information with a given flow
 *
 * @param frame_num The frame number
 * @param local_addr The local IPv4 or IPv6 address of the process
 * @param remote_addr The remote IPv4 or IPv6 address of the process
 * @param local_port The local TCP port of the process
 * @param remote_port The remote TCP port of the process
 * @param uid The numeric user ID of the process
 * @param pid The numeric PID of the process
 * @param username Ephemeral string containing the full or partial process name
 * @param command Ephemeral string containing the full or partial process name
 */
extern void add_tcp_process_info(uint32_t frame_num, address *local_addr, address *remote_addr, uint16_t local_port, uint16_t remote_port, uint32_t uid, uint32_t pid, char *username, char *command);

/** Get the current number of TCP streams
 *
 * @return The number of TCP streams
 */
WS_DLL_PUBLIC uint32_t get_tcp_stream_count(void);

/** Get the current number of MPTCP streams
 *
 * @return The number of MPTCP streams
 */
WS_DLL_PUBLIC uint32_t get_mptcp_stream_count(void);

/* Follow Stream functionality shared with HTTP (and SSL?) */
extern char *tcp_follow_conv_filter(epan_dissect_t *edt, packet_info *pinfo, unsigned *stream, unsigned *sub_stream);
extern char *tcp_follow_index_filter(unsigned stream, unsigned sub_stream);
extern char *tcp_follow_address_filter(address *src_addr, address *dst_addr, int src_port, int dst_port);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif