1/*
2 * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Axel D��rfler, axeld@pinc-software.de
7 *		Andrew Galante, haiku.galante@gmail.com
8 *		Hugo Santos, hugosantos@gmail.com
9 */
10#ifndef TCP_H
11#define TCP_H
12
13
14#include <net_buffer.h>
15#include <net_datalink.h>
16#include <net_socket.h>
17#include <net_stack.h>
18
19#include <ByteOrder.h>
20
21#include <sys/socket.h>
22
23
24class EndpointManager;
25
26enum tcp_state {
27	// establishing a connection
28	CLOSED,
29	LISTEN,
30	SYNCHRONIZE_SENT,
31	SYNCHRONIZE_RECEIVED,
32	ESTABLISHED,
33
34	// peer closes the connection
35	FINISH_RECEIVED,				// close-wait
36	WAIT_FOR_FINISH_ACKNOWLEDGE,	// last-ack
37
38	// we close the connection
39	FINISH_SENT,					// fin-wait-1
40	FINISH_ACKNOWLEDGED,			// fin-wait-2
41	CLOSING,
42	TIME_WAIT
43};
44
45struct tcp_header {
46	uint16	source_port;
47	uint16	destination_port;
48	uint32	sequence;
49	uint32	acknowledge;
50	struct {
51#if B_HOST_IS_LENDIAN == 1
52		uint8	reserved : 4;
53		uint8	header_length : 4;
54#else
55		uint8	header_length : 4;
56		uint8	reserved : 4;
57#endif
58	};
59	uint8	flags;
60	uint16	advertised_window;
61	uint16	checksum;
62	uint16	urgent_offset;
63
64	uint32	HeaderLength() const { return (uint32)header_length << 2; }
65	uint32	Sequence() const { return B_BENDIAN_TO_HOST_INT32(sequence); }
66	uint32	Acknowledge() const { return B_BENDIAN_TO_HOST_INT32(acknowledge); }
67	uint16	AdvertisedWindow() const { return B_BENDIAN_TO_HOST_INT16(advertised_window); }
68	uint16	Checksum() const { return B_BENDIAN_TO_HOST_INT16(checksum); }
69	uint16	UrgentOffset() const { return B_BENDIAN_TO_HOST_INT16(urgent_offset); }
70} _PACKED;
71
72class tcp_sequence {
73public:
74	inline tcp_sequence() {}
75	inline tcp_sequence(uint32 sequence)
76		: fNumber(sequence)
77	{
78	}
79
80	inline uint32 Number() const
81	{
82		return fNumber;
83	}
84
85	inline tcp_sequence& operator=(tcp_sequence sequence)
86	{
87		fNumber = sequence.fNumber;
88		return *this;
89	}
90
91	inline tcp_sequence& operator+=(tcp_sequence sequence)
92	{
93		fNumber += sequence.fNumber;
94		return *this;
95	}
96
97	inline tcp_sequence& operator++()
98	{
99		fNumber++;
100		return *this;
101	}
102
103	inline tcp_sequence operator++(int _)
104	{
105		fNumber++;
106		return fNumber - 1;
107	}
108
109private:
110	uint32	fNumber;
111};
112
113
114// Global tcp_sequence Operators
115
116
117inline bool
118operator>(tcp_sequence a, tcp_sequence b)
119{
120	return (int32)(a.Number() - b.Number()) > 0;
121}
122
123
124inline bool
125operator>=(tcp_sequence a, tcp_sequence b)
126{
127	return (int32)(a.Number() - b.Number()) >= 0;
128}
129
130
131inline bool
132operator<(tcp_sequence a, tcp_sequence b)
133{
134	return (int32)(a.Number() - b.Number()) < 0;
135}
136
137
138inline bool
139operator<=(tcp_sequence a, tcp_sequence b)
140{
141	return (int32)(a.Number() - b.Number()) <= 0;
142}
143
144
145inline tcp_sequence
146operator+(tcp_sequence a, tcp_sequence b)
147{
148	return a.Number() + b.Number();
149}
150
151
152inline tcp_sequence
153operator-(tcp_sequence a, tcp_sequence b)
154{
155	return a.Number() - b.Number();
156}
157
158
159inline bool
160operator!=(tcp_sequence a, tcp_sequence b)
161{
162	return a.Number() != b.Number();
163}
164
165
166inline bool
167operator==(tcp_sequence a, tcp_sequence b)
168{
169	return a.Number() == b.Number();
170}
171
172
173// TCP flag constants
174#define TCP_FLAG_FINISH					0x01
175#define TCP_FLAG_SYNCHRONIZE			0x02
176#define TCP_FLAG_RESET					0x04
177#define TCP_FLAG_PUSH					0x08
178#define TCP_FLAG_ACKNOWLEDGE			0x10
179#define TCP_FLAG_URGENT					0x20
180#define TCP_FLAG_CONGESTION_NOTIFICATION_ECHO	0x40
181#define TCP_FLAG_CONGESTION_WINDOW_REDUCED		0x80
182
183#define TCP_CONNECTION_TIMEOUT			75000000	// 75 secs
184#define TCP_DELAYED_ACKNOWLEDGE_TIMEOUT	100000		// 100 msecs
185#define TCP_DEFAULT_MAX_SEGMENT_SIZE	536
186#define TCP_MAX_WINDOW					65535
187#define TCP_MAX_SEGMENT_LIFETIME		60000000	// 60 secs
188#define TCP_PERSIST_TIMEOUT				1000000		// 1 sec
189
190// Initial estimate for packet round trip time (RTT)
191#define TCP_INITIAL_RTT					2000000		// 2 secs
192// Minimum retransmit timeout (consider delayed ack)
193#define TCP_MIN_RETRANSMIT_TIMEOUT		200000		// 200 msecs
194// Maximum retransmit timeout (per RFC6298)
195#define TCP_MAX_RETRANSMIT_TIMEOUT		60000000	// 60 secs
196// New value for timeout in case of lost SYN (RFC 6298)
197#define TCP_SYN_RETRANSMIT_TIMEOUT 		3000000		// 3 secs
198
199struct tcp_sack {
200	uint32 left_edge;
201	uint32 right_edge;
202} _PACKED;
203
204struct tcp_option {
205	uint8	kind;
206	uint8	length;
207	union {
208		uint8		window_shift;
209		uint16		max_segment_size;
210		struct {
211			uint32	value;
212			uint32	reply;
213		}			timestamp;
214		tcp_sack	sack[0];
215	};
216} _PACKED;
217
218enum tcp_option_kind {
219	TCP_OPTION_END				= 0,
220	TCP_OPTION_NOP				= 1,
221	TCP_OPTION_MAX_SEGMENT_SIZE	= 2,
222	TCP_OPTION_WINDOW_SHIFT		= 3,
223	TCP_OPTION_SACK_PERMITTED	= 4,
224	TCP_OPTION_SACK				= 5,
225	TCP_OPTION_TIMESTAMP		= 8,
226};
227
228#define TCP_MAX_WINDOW_SHIFT	14
229
230enum {
231	TCP_HAS_WINDOW_SCALE	= 1 << 0,
232	TCP_HAS_TIMESTAMPS		= 1 << 1,
233	TCP_SACK_PERMITTED		= 1 << 2,
234	TCP_HAS_SACK			= 1 << 3,
235};
236
237struct tcp_segment_header {
238	tcp_segment_header(uint8 _flags)
239		:
240		flags(_flags),
241		window_shift(0),
242		max_segment_size(0),
243		sackCount(0),
244		options(0)
245	{}
246
247	uint32	sequence;
248	uint32	acknowledge;
249	uint16	advertised_window;
250	uint16	urgent_offset;
251	uint8	flags;
252	uint8	window_shift;
253	uint16	max_segment_size;
254
255	uint32	timestamp_value;
256	uint32	timestamp_reply;
257
258#define MAX_SACK_BLKS 4
259	tcp_sack	sacks[MAX_SACK_BLKS];
260	int			sackCount;
261
262	uint32	options;
263
264	bool AcknowledgeOnly() const
265	{
266		return (flags & (TCP_FLAG_SYNCHRONIZE | TCP_FLAG_FINISH | TCP_FLAG_RESET
267			| TCP_FLAG_URGENT | TCP_FLAG_ACKNOWLEDGE)) == TCP_FLAG_ACKNOWLEDGE;
268	}
269
270	uint32 AdvertisedWindow(uint8 windowShift) const
271	{
272		return (uint32)advertised_window << windowShift;
273	}
274	void SetAdvertisedWindow(size_t availableBytes, uint8 windowShift)
275	{
276		availableBytes >>= windowShift;
277		advertised_window = min_c(TCP_MAX_WINDOW, availableBytes);
278	}
279};
280
281enum tcp_segment_action {
282	KEEP					= 0,
283	DROP					= (1 << 0),
284	RESET					= (1 << 1),
285	ACKNOWLEDGE				= (1 << 2),
286	IMMEDIATE_ACKNOWLEDGE	= (1 << 3),
287	SEND_QUEUED				= (1 << 4),
288	DELETED_ENDPOINT		= (1 << 5),
289};
290
291
292extern net_buffer_module_info* gBufferModule;
293extern net_datalink_module_info* gDatalinkModule;
294extern net_socket_module_info* gSocketModule;
295extern net_stack_module_info* gStackModule;
296
297
298EndpointManager* get_endpoint_manager(net_domain* domain);
299void put_endpoint_manager(EndpointManager* manager);
300
301status_t add_tcp_header(net_address_module_info* addressModule,
302	tcp_segment_header& segment, net_buffer* buffer);
303size_t tcp_options_length(tcp_segment_header& segment);
304
305const char* name_for_state(tcp_state state);
306
307#endif	// TCP_H
308