#ifndef TCP_H
#define TCP_H
#include <net_buffer.h>
#include <net_datalink.h>
#include <net_socket.h>
#include <net_stack.h>
#include <ByteOrder.h>
#include <sys/socket.h>
class EndpointManager;
enum tcp_state {
CLOSED,
LISTEN,
SYNCHRONIZE_SENT,
SYNCHRONIZE_RECEIVED,
ESTABLISHED,
FINISH_RECEIVED,
WAIT_FOR_FINISH_ACKNOWLEDGE,
FINISH_SENT,
FINISH_ACKNOWLEDGED,
CLOSING,
TIME_WAIT
};
struct tcp_header {
uint16 source_port;
uint16 destination_port;
uint32 sequence;
uint32 acknowledge;
struct {
#if B_HOST_IS_LENDIAN == 1
uint8 reserved : 4;
uint8 header_length : 4;
#else
uint8 header_length : 4;
uint8 reserved : 4;
#endif
};
uint8 flags;
uint16 advertised_window;
uint16 checksum;
uint16 urgent_offset;
uint32 HeaderLength() const { return (uint32)header_length << 2; }
uint32 Sequence() const { return B_BENDIAN_TO_HOST_INT32(sequence); }
uint32 Acknowledge() const { return B_BENDIAN_TO_HOST_INT32(acknowledge); }
uint16 AdvertisedWindow() const { return B_BENDIAN_TO_HOST_INT16(advertised_window); }
uint16 Checksum() const { return B_BENDIAN_TO_HOST_INT16(checksum); }
uint16 UrgentOffset() const { return B_BENDIAN_TO_HOST_INT16(urgent_offset); }
} _PACKED;
class tcp_sequence {
public:
inline tcp_sequence() {}
inline tcp_sequence(uint32 sequence)
: fNumber(sequence)
{
}
inline uint32 Number() const
{
return fNumber;
}
inline tcp_sequence& operator=(tcp_sequence sequence)
{
fNumber = sequence.fNumber;
return *this;
}
inline tcp_sequence& operator+=(tcp_sequence sequence)
{
fNumber += sequence.fNumber;
return *this;
}
inline tcp_sequence& operator++()
{
fNumber++;
return *this;
}
inline tcp_sequence operator++(int _)
{
fNumber++;
return fNumber - 1;
}
private:
uint32 fNumber;
};
inline bool
operator>(tcp_sequence a, tcp_sequence b)
{
return (int32)(a.Number() - b.Number()) > 0;
}
inline bool
operator>=(tcp_sequence a, tcp_sequence b)
{
return (int32)(a.Number() - b.Number()) >= 0;
}
inline bool
operator<(tcp_sequence a, tcp_sequence b)
{
return (int32)(a.Number() - b.Number()) < 0;
}
inline bool
operator<=(tcp_sequence a, tcp_sequence b)
{
return (int32)(a.Number() - b.Number()) <= 0;
}
inline tcp_sequence
operator+(tcp_sequence a, tcp_sequence b)
{
return a.Number() + b.Number();
}
inline tcp_sequence
operator-(tcp_sequence a, tcp_sequence b)
{
return a.Number() - b.Number();
}
inline bool
operator!=(tcp_sequence a, tcp_sequence b)
{
return a.Number() != b.Number();
}
inline bool
operator==(tcp_sequence a, tcp_sequence b)
{
return a.Number() == b.Number();
}
#define TCP_FLAG_FINISH 0x01
#define TCP_FLAG_SYNCHRONIZE 0x02
#define TCP_FLAG_RESET 0x04
#define TCP_FLAG_PUSH 0x08
#define TCP_FLAG_ACKNOWLEDGE 0x10
#define TCP_FLAG_URGENT 0x20
#define TCP_FLAG_CONGESTION_NOTIFICATION_ECHO 0x40
#define TCP_FLAG_CONGESTION_WINDOW_REDUCED 0x80
#define TCP_CONNECTION_TIMEOUT 75000000
#define TCP_DELAYED_ACKNOWLEDGE_TIMEOUT 100000
#define TCP_DEFAULT_MAX_SEGMENT_SIZE 536
#define TCP_MAX_WINDOW 65535
#define TCP_MAX_SEGMENT_LIFETIME 60000000
#define TCP_PERSIST_TIMEOUT 1000000
#define TCP_MIN_RETRANSMIT_TIMEOUT 200000
#define TCP_MAX_RETRANSMIT_TIMEOUT 60000000
#define TCP_SYN_RETRANSMIT_TIMEOUT 1000000
struct tcp_sack {
uint32 left_edge;
uint32 right_edge;
} _PACKED;
struct tcp_option {
uint8 kind;
uint8 length;
union {
uint8 window_shift;
uint16 max_segment_size;
struct {
uint32 value;
uint32 reply;
} timestamp;
tcp_sack sack[0];
};
} _PACKED;
enum tcp_option_kind {
TCP_OPTION_END = 0,
TCP_OPTION_NOP = 1,
TCP_OPTION_MAX_SEGMENT_SIZE = 2,
TCP_OPTION_WINDOW_SHIFT = 3,
TCP_OPTION_SACK_PERMITTED = 4,
TCP_OPTION_SACK = 5,
TCP_OPTION_TIMESTAMP = 8,
};
#define TCP_MAX_WINDOW_SHIFT 14
enum {
TCP_HAS_WINDOW_SCALE = 1 << 0,
TCP_HAS_TIMESTAMPS = 1 << 1,
TCP_SACK_PERMITTED = 1 << 2,
TCP_HAS_SACK = 1 << 3,
};
struct tcp_segment_header {
tcp_segment_header(uint8 _flags)
:
flags(_flags),
window_shift(0),
max_segment_size(0),
sackCount(0),
options(0)
{}
uint32 sequence;
uint32 acknowledge;
uint16 advertised_window;
uint16 urgent_offset;
uint8 flags;
uint8 window_shift;
uint16 max_segment_size;
uint32 timestamp_value;
uint32 timestamp_reply;
#define MAX_SACK_BLKS 4
tcp_sack sacks[MAX_SACK_BLKS];
int sackCount;
uint32 options;
bool AcknowledgeOnly() const
{
return (flags & (TCP_FLAG_SYNCHRONIZE | TCP_FLAG_FINISH | TCP_FLAG_RESET
| TCP_FLAG_URGENT | TCP_FLAG_ACKNOWLEDGE)) == TCP_FLAG_ACKNOWLEDGE;
}
uint32 AdvertisedWindow(uint8 windowShift) const
{
return (uint32)advertised_window << windowShift;
}
void SetAdvertisedWindow(size_t availableBytes, uint8 windowShift)
{
availableBytes >>= windowShift;
advertised_window = min_c(TCP_MAX_WINDOW, availableBytes);
}
};
enum tcp_segment_action {
KEEP = 0,
DROP = (1 << 0),
RESET = (1 << 1),
ACKNOWLEDGE = (1 << 2),
IMMEDIATE_ACKNOWLEDGE = (1 << 3),
SEND_QUEUED = (1 << 4),
DELETED_ENDPOINT = (1 << 5),
};
extern net_buffer_module_info* gBufferModule;
extern net_datalink_module_info* gDatalinkModule;
extern net_socket_module_info* gSocketModule;
extern net_stack_module_info* gStackModule;
EndpointManager* get_endpoint_manager(net_domain* domain);
void put_endpoint_manager(EndpointManager* manager);
status_t add_tcp_header(net_address_module_info* addressModule,
tcp_segment_header& segment, net_buffer* buffer);
size_t tcp_options_length(tcp_segment_header& segment);
const char* name_for_state(tcp_state state);
#endif