diff --git a/headers/private/kernel/boot/net/NetDefs.h b/headers/private/kernel/boot/net/NetDefs.h
index d190ff6..041e1ee 100644
--- a/headers/private/kernel/boot/net/NetDefs.h
+++ b/headers/private/kernel/boot/net/NetDefs.h
@@ -1,5 +1,6 @@
 /*
  * Copyright 2005, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
+ * Copyright 2010, Andreas Faerber <andreas.faerber@web.de>
  * All rights reserved. Distributed under the terms of the MIT License.
  */
 
@@ -157,6 +158,7 @@ struct ip_header {
 #define IP_DEFAULT_TIME_TO_LIVE		64		/* default ttl, from RFC 1340 */
 
 // IP protocols
+#define IPPROTO_TCP					6
 #define IPPROTO_UDP					17
 
 
@@ -174,6 +176,46 @@ struct udp_header
 } __attribute__ ((__packed__));
 
 
+// Transmission Control Protocol (TCP)
+
+// TCP header (RFC 793, RFC 3168)
+struct tcp_header
+{
+	uint16 source;			// source port
+	uint16 destination;		// destination port
+	uint32 seqNumber;		// sequence number
+	uint32 ackNumber;		// acknowledgment number
+#if __BYTE_ORDER == __BIG_ENDIAN
+	uint8 dataOffset:4;		// data offset
+	uint8 reserved:4;		// reserved
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+	uint8 reserved:4;		// reserved
+	uint8 dataOffset:4;		// data offset
+#endif
+#if __BYTE_ORDER == __BIG_ENDIAN
+	bool cwr:1;
+	bool ece:1;
+	bool urg:1;
+	bool ack:1;
+	bool psh:1;
+	bool rst:1;
+	bool syn:1;
+	bool fin:1;
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+	bool fin:1;
+	bool syn:1;
+	bool rst:1;
+	bool psh:1;
+	bool ack:1;
+	bool urg:1;
+	bool ece:1;
+	bool cwr:1;
+#endif
+	uint16 window;			// window size
+	uint16 checksum;		// checksum
+	uint16 urgentPointer;   // urgent pointer
+} __attribute__ ((__packed__));
+
 // #pragma mark -
 
 // NetService
@@ -183,6 +225,7 @@ extern const char *const kEthernetServiceName;
 extern const char *const kARPServiceName;
 extern const char *const kIPServiceName;
 extern const char *const kUDPServiceName;
+extern const char *const kTCPServiceName;
 
 class NetService {
 public:
diff --git a/headers/private/kernel/boot/net/NetStack.h b/headers/private/kernel/boot/net/NetStack.h
index e2baeaa..f148732 100644
--- a/headers/private/kernel/boot/net/NetStack.h
+++ b/headers/private/kernel/boot/net/NetStack.h
@@ -13,6 +13,7 @@ class EthernetService;
 class ARPService;
 class IPService;
 class UDPService;
+class TCPService;
 
 
 class NetStack {
@@ -34,6 +35,7 @@ public:
 	ARPService *GetARPService() const			{ return fARPService; }
 	IPService *GetIPService() const				{ return fIPService; }
 	UDPService *GetUDPService() const			{ return fUDPService; }
+	TCPService *GetTCPService() const			{ return fTCPService; }
 
 private:
 	static NetStack		*sNetStack;
@@ -43,6 +45,7 @@ private:
 	ARPService			*fARPService;
 	IPService			*fIPService;
 	UDPService			*fUDPService;
+	TCPService			*fTCPService;
 };
 
 
diff --git a/headers/private/kernel/boot/net/TCP.h b/headers/private/kernel/boot/net/TCP.h
new file mode 100644
index 0000000..43707f3
--- /dev/null
+++ b/headers/private/kernel/boot/net/TCP.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2010 Andreas Faerber <andreas.faerber@web.de>
+ * All rights reserved. Distributed under the terms of the MIT License.
+ */
+
+#ifndef BOOT_NET_TCP_H
+#define BOOT_NET_TCP_H
+
+#include <boot/net/IP.h>
+
+
+class TCPPacket {
+public:
+	TCPPacket();
+	~TCPPacket();
+
+	status_t SetTo(const void* data, size_t size, ip_addr_t sourceAddress,
+		uint16 sourcePort, ip_addr_t destinationAddress,
+		uint16 destinationPort, uint32 sequenceNumber,
+		uint32 acknowledgmentNumber, uint8 flags);
+
+	ip_addr_t SourceAddress() const;
+	ip_addr_t DestinationAddress() const;
+	uint16 SourcePort() const;
+	uint16 DestinationPort() const;
+	uint32 SequenceNumber() const;
+	uint32 AcknowledgmentNumber() const;
+	const void* Data() const { return fData; }
+	size_t DataSize() const { return fSize; }
+	uint8 Flags() const { return fFlags; }
+
+	TCPPacket* Next() const;
+	void SetNext(TCPPacket* packet);
+
+private:
+	ip_addr_t	fSourceAddress;
+	ip_addr_t	fDestinationAddress;
+	uint16		fSourcePort;
+	uint16		fDestinationPort;
+	uint32		fSequenceNumber;
+	uint32		fAcknowledgmentNumber;
+	void*		fData;
+	size_t		fSize;
+	uint8		fFlags;
+	TCPPacket*	fNext;
+};
+
+#define TCP_SYN		1
+#define TCP_ACK		2
+#define TCP_FIN		4
+#define TCP_RST		8
+
+class TCPService;
+
+enum TCPSocketState {
+	TCP_SOCKET_STATE_INITIAL,
+	TCP_SOCKET_STATE_SYN_SENT,
+	TCP_SOCKET_STATE_SYN_RECEIVED,
+	TCP_SOCKET_STATE_OPEN,
+	TCP_SOCKET_STATE_FIN_SENT,
+	TCP_SOCKET_STATE_CLOSED
+};
+
+class TCPSocket {
+public:
+	TCPSocket();
+	~TCPSocket();
+
+	ip_addr_t Address() const	{ return fAddress; }
+	uint16 Port() const			{ return fPort; }
+
+	status_t Connect(ip_addr_t address, uint16 port);
+	status_t Close();
+	status_t Receive(TCPPacket** packet, bigtime_t timeout = 0);
+
+	void Acknowledge(uint32 number);
+	void ProcessPacket(TCPPacket* packet);
+	TCPPacket* DequeuePacket();
+	TCPPacket* PopPacket();
+
+private:
+	status_t _Send(TCPPacket* packet);
+	status_t _ResendQueue();
+	void _EnqueueOutgoingPacket(TCPPacket* packet);
+	status_t _WaitForState(TCPSocketState state, bigtime_t timeout = 0);
+	status_t _Ack();
+
+	TCPService*	fTCPService;
+	ip_addr_t	fAddress;
+	uint16		fPort;
+	ip_addr_t	fRemoteAddress;
+	uint16		fRemotePort;
+	uint32		fSequenceNumber;
+	uint32		fAcknowledgeNumber;
+	uint32		fNextPacket;
+	TCPPacket*	fFirstPacket;
+	TCPPacket*	fLastPacket;
+	TCPPacket*	fFirstSentPacket;
+	TCPPacket*	fLastSentPacket;
+	TCPSocketState fState;
+	TCPSocketState fRemoteState;
+};
+
+class TCPService : public IPSubService {
+public:
+	TCPService(IPService* ipService);
+	virtual ~TCPService();
+
+	status_t Init();
+
+	virtual uint8 IPProtocol() const;
+
+	virtual void HandleIPPacket(IPService* ipService, ip_addr_t sourceIP,
+		ip_addr_t destinationIP, const void* data, size_t size);
+
+	status_t Send(uint16 sourcePort, ip_addr_t destinationAddress,
+		uint16 destinationPort, uint32 sequenceNumber,
+		uint32 acknowledgmentNumber, uint8 flags, ChainBuffer* buffer);
+
+	void ProcessIncomingPackets();
+
+	status_t BindSocket(TCPSocket* socket);
+	void UnbindSocket(TCPSocket* socket);
+
+private:
+	uint16 _ChecksumBuffer(ChainBuffer* buffer, ip_addr_t source,
+		ip_addr_t destination, uint16 length);
+	uint16 _ChecksumData(const void* data, uint16 length, ip_addr_t source,
+		ip_addr_t destination);
+
+	TCPSocket* _FindSocket(ip_addr_t address, uint16 port);
+
+	IPService*			fIPService;
+	Vector<TCPSocket*>	fSockets;
+};
+
+#endif
diff --git a/src/system/boot/loader/net/Jamfile b/src/system/boot/loader/net/Jamfile
index 8555a7d..8a8245f 100644
--- a/src/system/boot/loader/net/Jamfile
+++ b/src/system/boot/loader/net/Jamfile
@@ -13,6 +13,7 @@ KernelStaticLibrary boot_net :
 	NetStack.cpp
 	RemoteDisk.cpp
 	UDP.cpp
+	TCP.cpp
 
 	: -fno-pic
 ;
diff --git a/src/system/boot/loader/net/NetDefs.cpp b/src/system/boot/loader/net/NetDefs.cpp
index 009e4c0..19b7681 100644
--- a/src/system/boot/loader/net/NetDefs.cpp
+++ b/src/system/boot/loader/net/NetDefs.cpp
@@ -16,6 +16,7 @@ const char *const kEthernetServiceName = "ethernet";
 const char *const kARPServiceName = "arp";
 const char *const kIPServiceName = "ip";
 const char *const kUDPServiceName = "udp";
+const char *const kTCPServiceName = "tcp";
 
 
 // constructor
diff --git a/src/system/boot/loader/net/NetStack.cpp b/src/system/boot/loader/net/NetStack.cpp
index 7db3de0..0154997 100644
--- a/src/system/boot/loader/net/NetStack.cpp
+++ b/src/system/boot/loader/net/NetStack.cpp
@@ -13,6 +13,7 @@
 #include <boot/net/Ethernet.h>
 #include <boot/net/IP.h>
 #include <boot/net/UDP.h>
+#include <boot/net/TCP.h>
 
 
 // sNetStack
@@ -24,13 +25,15 @@ NetStack::NetStack()
 		fEthernetService(NULL),
 		fARPService(NULL),
 		fIPService(NULL),
-		fUDPService(NULL)
+		fUDPService(NULL),
+		fTCPService(NULL)
 {
 }
 
 // destructor
 NetStack::~NetStack()
 {
+	delete fTCPService;
 	delete fUDPService;
 	delete fIPService;
 	delete fARPService;
@@ -73,6 +76,14 @@ NetStack::Init()
 	if (error != B_OK)
 		return error;
 
+	// TCP service
+	fTCPService = new(nothrow) TCPService(fIPService);
+	if (fTCPService == NULL)
+		return B_NO_MEMORY;
+	error = fTCPService->Init();
+	if (error != B_OK)
+		return error;
+
 	return B_OK;
 }
 
diff --git a/src/system/boot/loader/net/TCP.cpp b/src/system/boot/loader/net/TCP.cpp
new file mode 100644
index 0000000..2c004fd
--- /dev/null
+++ b/src/system/boot/loader/net/TCP.cpp
@@ -0,0 +1,643 @@
+/*
+ * Copyright 2010 Andreas Faerber <andreas.faerber@web.de>
+ * All rights reserved. Distributed under the terms of the MIT License.
+ */
+
+#include <boot/net/TCP.h>
+
+#include <stdio.h>
+#include <KernelExport.h>
+
+#include <boot/net/ChainBuffer.h>
+#include <boot/net/NetStack.h>
+
+
+//#define TRACE_TCP
+#ifdef TRACE_TCP
+#	define TRACE(x) dprintf x
+#else
+#	define TRACE(x) ;
+#endif
+
+
+TCPPacket::TCPPacket()
+	:
+	fNext(NULL)
+{
+}
+
+
+TCPPacket::~TCPPacket()
+{
+}
+
+
+status_t
+TCPPacket::SetTo(const void* data, size_t size, ip_addr_t sourceAddress,
+	uint16 sourcePort, ip_addr_t destinationAddress, uint16 destinationPort,
+	uint32 sequenceNumber, uint32 acknowledgmentNumber, uint8 flags)
+{
+	if (data == NULL && size > 0)
+		return B_BAD_VALUE;
+
+	if (size > 0) {
+		fData = malloc(size);
+		if (fData == NULL)
+			return B_NO_MEMORY;
+		memcpy(fData, data, size);
+	} else {
+		fData = NULL;
+	}
+
+	fSize = size;
+	fSourceAddress = sourceAddress;
+	fSourcePort = sourcePort;
+	fDestinationAddress = destinationAddress;
+	fDestinationPort = destinationPort;
+	fSequenceNumber = sequenceNumber;
+	fAcknowledgmentNumber = acknowledgmentNumber;
+	fFlags = flags;
+
+	return B_OK;
+}
+
+
+ip_addr_t
+TCPPacket::SourceAddress() const
+{
+	return fSourceAddress;
+}
+
+
+ip_addr_t
+TCPPacket::DestinationAddress() const
+{
+	return fDestinationAddress;
+}
+
+
+uint16
+TCPPacket::SourcePort() const
+{
+	return fSourcePort;
+}
+
+
+uint16
+TCPPacket::DestinationPort() const
+{
+	return fDestinationPort;
+}
+
+
+uint32
+TCPPacket::SequenceNumber() const
+{
+	return fSequenceNumber;
+}
+
+
+uint32
+TCPPacket::AcknowledgmentNumber() const
+{
+	return fAcknowledgmentNumber;
+}
+
+
+TCPPacket*
+TCPPacket::Next() const
+{
+	return fNext;
+}
+
+
+void
+TCPPacket::SetNext(TCPPacket* packet)
+{
+	fNext = packet;
+}
+
+
+
+
+TCPSocket::TCPSocket()
+	:
+	fTCPService(NetStack::Default()->GetTCPService()),
+	fAddress(INADDR_ANY),
+	fPort(0),
+	fSequenceNumber(0),
+	fFirstPacket(NULL),
+	fLastPacket(NULL),
+	fFirstSentPacket(NULL),
+	fLastSentPacket(NULL),
+	fState(TCP_SOCKET_STATE_INITIAL),
+	fRemoteState(TCP_SOCKET_STATE_INITIAL)
+{
+}
+
+
+TCPSocket::~TCPSocket()
+{
+	if (fTCPService != NULL && fPort != 0)
+		fTCPService->UnbindSocket(this);
+}
+
+
+status_t
+TCPSocket::Connect(ip_addr_t address, uint16 port)
+{
+	fRemoteAddress = address;
+	fRemotePort = port;
+	TRACE(("time %llu\n", system_time()));
+	fSequenceNumber = system_time();
+	uint16 random = system_time();
+	fPort = 0xC000 + (random & ~0xc000);
+	fAcknowledgeNumber = 0;
+	fNextPacket = 0;
+
+	status_t error = fTCPService->BindSocket(this);
+	if (error != B_OK)
+		return error;
+
+	// send SYN
+	TCPPacket* packet = new(nothrow) TCPPacket();
+	if (packet == NULL)
+		return B_NO_MEMORY;
+	error = packet->SetTo(NULL, 0, fAddress, fPort, address, port,
+		fSequenceNumber, fAcknowledgeNumber, TCP_SYN);
+	if (error != B_OK)
+		return error;
+	error = _Send(packet);
+	if (error != B_OK)
+		return error;
+	fState = TCP_SOCKET_STATE_SYN_SENT;
+	TRACE(("SYN sent\n"));
+
+	// receive SYN-ACK
+	error = _WaitForState(TCP_SOCKET_STATE_OPEN, 1000000LL);
+	if (error != B_OK) {
+		TRACE(("no SYN-ACK received\n"));
+		return error;
+	}
+	TRACE(("SYN-ACK received\n"));
+
+	return B_OK;
+}
+
+
+status_t
+TCPSocket::Close()
+{
+	// send FIN
+	TCPPacket* packet = new(nothrow) TCPPacket();
+	if (packet == NULL)
+		return B_NO_MEMORY;
+	status_t error = packet->SetTo(NULL, 0, fAddress, fPort, fRemoteAddress, fRemotePort,
+		fSequenceNumber, fAcknowledgeNumber, TCP_FIN | TCP_ACK);
+	if (error != B_OK)
+		return error;
+	error = _Send(packet);
+	if (error != B_OK)
+		return error;
+	fState = TCP_SOCKET_STATE_FIN_SENT;
+	TRACE(("FIN sent\n"));
+
+	error = _WaitForState(TCP_SOCKET_STATE_CLOSED, 1000000LL);
+	if (error != B_OK)
+		return error;
+
+	return B_OK;
+}
+
+
+status_t
+TCPSocket::Receive(TCPPacket** _packet, bigtime_t timeout)
+{
+	if (fTCPService == NULL)
+		return B_NO_INIT;
+	if (_packet == NULL)
+		return B_BAD_VALUE;
+	bigtime_t startTime = system_time();
+	do {
+		fTCPService->ProcessIncomingPackets();
+		TCPPacket* packet = DequeuePacket();
+		if (packet != NULL) {
+			*_packet = packet;
+			return B_OK;
+		}
+		_ResendQueue();
+	} while (system_time() - startTime < timeout);
+	return timeout == 0 ? B_WOULD_BLOCK : B_TIMED_OUT;
+}
+
+
+void
+TCPSocket::Acknowledge(uint32 number)
+{
+	TRACE(("TCPSocket::Acknowledge(): %lu\n", number));
+	// dequeue packets
+	for (TCPPacket* packet = fFirstSentPacket; packet != NULL;
+			packet = fFirstSentPacket) {
+		if (packet->SequenceNumber() > number ||
+				(packet->SequenceNumber() == number && packet->DataSize() > 0))
+			return;
+		fFirstSentPacket = packet->Next();
+		delete packet;
+	}
+	fLastSentPacket = NULL;
+}
+
+
+void
+TCPSocket::ProcessPacket(TCPPacket* packet)
+{
+	TRACE(("TCPSocket::ProcessPacket()\n"));
+
+	if ((packet->Flags() & TCP_FIN) != 0) {
+		fRemoteState = TCP_SOCKET_STATE_FIN_SENT;
+		TRACE(("FIN received\n"));
+		_Ack();
+	}
+
+	if (fState == TCP_SOCKET_STATE_SYN_SENT) {
+		if ((packet->Flags() & TCP_SYN) != 0
+				&& (packet->Flags() & TCP_ACK) != 0) {
+			fNextPacket = fAcknowledgeNumber = packet->SequenceNumber() + 1;
+			fRemoteState = TCP_SOCKET_STATE_SYN_SENT;
+			delete packet;
+			_Ack();
+			fState = fRemoteState = TCP_SOCKET_STATE_OPEN;
+			return;
+		}
+	} else if (fState == TCP_SOCKET_STATE_OPEN) {
+	} else if (fState == TCP_SOCKET_STATE_FIN_SENT) {
+		if ((packet->Flags() & TCP_ACK) != 0) {
+			TRACE(("FIN-ACK received\n"));
+			if (fRemoteState == TCP_SOCKET_STATE_FIN_SENT)
+				fState = TCP_SOCKET_STATE_CLOSED;
+		}
+	}
+
+	/*if (fLastPacket == NULL) {
+		// no packets enqueued
+		packet->SetNext(NULL);
+		fFirstPacket = fLastPacket = packet;
+	} else if (fLastPacket->SequenceNumber() < packet->SequenceNumber()) {
+		// enqueue in back
+		fLastPacket->SetNext(packet);
+		fLastPacket = packet;
+	} else if (fFirstPacket->SequenceNumber() > packet->SequenceNumber()) {
+		// enqueue in front
+		packet->SetNext(fFirstPacket);
+		fFirstPacket = packet;
+	} else {
+		// enqueue in middle
+		for (TCPPacket* queuedPacket = fFirstPacket; queuedPacket != NULL;
+				queuedPacket = queuedPacket->Next()) {
+			if (queuedPacket->SequenceNumber() == packet->SequenceNumber()) {
+				TRACE(("TCPSocket::EnqueuePacket(): TCP packet dropped\n"));
+				// we may be waiting for a previous packet
+				return;
+			}
+			if (queuedPacket->Next()->SequenceNumber() > packet->SequenceNumber()) {
+				packet->SetNext(queuedPacket->Next());
+				queuedPacket->SetNext(packet);
+				break;
+			}
+		}
+	}*/
+}
+
+
+TCPPacket*
+TCPSocket::DequeuePacket()
+{
+	//TRACE(("TCPSocket::DequeuePacket()\n"));
+	if (fFirstPacket == NULL)
+		return NULL;
+
+	if (fFirstPacket->SequenceNumber() == fNextPacket)
+		return PopPacket();
+
+	for (TCPPacket* packet = fFirstPacket;
+			packet != NULL && packet->Next() != NULL;
+			packet = packet->Next()) {
+		if (packet->Next()->SequenceNumber() == fNextPacket) {
+			TCPPacket* nextPacket = packet->Next();
+			packet->SetNext(nextPacket->Next());
+			if (fLastPacket == nextPacket)
+				fLastPacket = packet;
+			fNextPacket += nextPacket->DataSize();
+			return nextPacket;
+		}
+	}
+	return NULL;
+}
+
+
+TCPPacket*
+TCPSocket::PopPacket()
+{
+	//TRACE(("TCPSocket::PopPacket()\n"));
+	if (fFirstPacket == NULL)
+		return NULL;
+
+	TCPPacket* packet = fFirstPacket;
+	fFirstPacket = packet->Next();
+	if (fFirstPacket == NULL)
+		fLastPacket = NULL;
+	packet->SetNext(NULL);
+	return packet;
+}
+
+
+status_t
+TCPSocket::_Send(TCPPacket* packet)
+{
+	ChainBuffer buffer((void*)packet->Data(), packet->DataSize());
+	status_t error = fTCPService->Send(fPort, fRemoteAddress, fRemotePort,
+		packet->SequenceNumber(), fAcknowledgeNumber, packet->Flags(),
+		&buffer);
+	if (error != B_OK)
+		return error;
+	fSequenceNumber += packet->DataSize();
+	_EnqueueOutgoingPacket(packet);
+	return B_OK;
+}
+
+
+status_t
+TCPSocket::_ResendQueue()
+{
+	TRACE(("TCPSocket::_ResendQueue()\n"));
+	for (TCPPacket* packet = fFirstSentPacket; packet != NULL;
+			packet = packet->Next()) {
+		ChainBuffer buffer((void*)packet->Data(), packet->DataSize());
+		status_t error = fTCPService->Send(fPort, fRemoteAddress, fRemotePort,
+			packet->SequenceNumber(), fAcknowledgeNumber, packet->Flags(),
+			&buffer);
+		if (error != B_OK)
+			return error;
+	}
+	return B_OK;
+}
+
+
+void
+TCPSocket::_EnqueueOutgoingPacket(TCPPacket* packet)
+{
+	if (fLastSentPacket != NULL) {
+		fLastSentPacket->SetNext(packet);
+		fLastSentPacket = packet;
+	} else {
+		fFirstSentPacket = fLastSentPacket = packet;
+	}
+}
+
+
+status_t
+TCPSocket::_Ack()
+{
+	TCPPacket* packet = new(nothrow) TCPPacket();
+	if (packet == NULL)
+		return B_NO_MEMORY;
+	status_t error = packet->SetTo(NULL, 0, fAddress, fPort, fRemoteAddress,
+		fRemotePort, fSequenceNumber, fAcknowledgeNumber, TCP_ACK);
+	if (error != B_OK)
+		return error;
+	error = _Send(packet);
+	if (error != B_OK)
+		return error;
+	return B_OK;
+}
+
+
+status_t
+TCPSocket::_WaitForState(TCPSocketState state, bigtime_t timeout)
+{
+	if (fTCPService == NULL)
+		return B_NO_INIT;
+
+	bigtime_t startTime = system_time();
+	do {
+		fTCPService->ProcessIncomingPackets();
+		if (fState == state)
+			return B_OK;
+	} while (system_time() - startTime < timeout);
+	return timeout == 0 ? B_WOULD_BLOCK : B_TIMED_OUT;
+}
+
+
+
+
+TCPService::TCPService(IPService* ipService)
+	:
+	IPSubService(kTCPServiceName),
+	fIPService(ipService)
+{
+}
+
+
+TCPService::~TCPService()
+{
+	if (fIPService != NULL)
+		fIPService->UnregisterIPSubService(this);
+}
+
+
+status_t
+TCPService::Init()
+{
+	if (fIPService == NULL)
+		return B_BAD_VALUE;
+	if (!fIPService->RegisterIPSubService(this))
+		return B_NO_MEMORY;
+	return B_OK;
+}
+
+
+uint8
+TCPService::IPProtocol() const
+{
+	return IPPROTO_TCP;
+}
+
+
+void
+TCPService::HandleIPPacket(IPService* ipService, ip_addr_t sourceIP,
+	ip_addr_t destinationIP, const void* data, size_t size)
+{
+	TRACE(("TCPService::HandleIPPacket(): source = %08lx, destination = %08lx, "
+		"%lu - %lu bytes\n", sourceIP, destinationIP, size, sizeof(tcp_header)));
+
+	if (data == NULL || size < sizeof(tcp_header))
+		return;
+
+	const tcp_header* header = (const tcp_header*)data;
+	uint16 source = ntohs(header->source);
+	uint16 destination = ntohs(header->destination);
+	uint32 sequenceNumber = ntohl(header->seqNumber);
+	uint32 ackedNumber = ntohl(header->ackNumber);
+	uint8 flags = 0;
+	if (header->syn)
+		flags |= TCP_SYN;
+	if (header->ack)
+		flags |= TCP_ACK;
+	if (header->fin)
+		flags |= TCP_FIN;
+	if (header->rst)
+		flags |= TCP_RST;
+	TRACE(("\tsource = %u, dest = %u, seq = %lu, ack = %lu, dataOffset = %u, flags %s %s %s %s\n",
+		source, destination, sequenceNumber, ackedNumber, header->dataOffset,
+		header->ack ? "ACK" : "", header->syn ? "SYN" : "", header->fin ? "FIN" : "", header->rst ? "RST" : ""));
+	if (header->dataOffset > 5) {
+		uint8* option = (uint8*)data + sizeof(tcp_header);
+		while ((uint32*)option < (uint32*)data + header->dataOffset) {
+			uint8 optionKind = option[0];
+			uint8 optionLength = 1;
+			if (optionKind > 1)
+				optionLength = option[1];
+			TRACE(("\tTCP option kind %u, length %u\n", optionKind, optionLength));
+			option += optionLength;
+		}
+	}
+
+	uint16 chksum = _ChecksumData(data, size, sourceIP, destinationIP);
+	if (chksum != 0) {
+		TRACE(("TCPService::HandleIPPacket(): invalid checksum (%04x)\n", header->checksum));
+		//return;
+	}
+
+	TCPSocket* socket = _FindSocket(destinationIP, destination);
+	if (socket == NULL) {
+		//TODO if SYN, answer with RST?
+		return;
+	}
+
+	if (header->ack) {
+		socket->Acknowledge(ackedNumber);
+	}
+
+	TCPPacket* packet = new(nothrow) TCPPacket();
+	if (packet == NULL)
+		return;
+	status_t error = packet->SetTo((uint32*)data + header->dataOffset,
+		size - header->dataOffset * 4, sourceIP, source, destinationIP,
+		destination, sequenceNumber, ackedNumber, flags);
+	if (error == B_OK)
+		socket->ProcessPacket(packet);
+	else
+		delete packet;
+}
+
+
+status_t
+TCPService::Send(uint16 sourcePort, ip_addr_t destinationAddress,
+	uint16 destinationPort, uint32 sequenceNumber,
+	uint32 acknowledgmentNumber, uint8 flags, ChainBuffer* buffer)
+{
+	TRACE(("TCPService::Send(): seq = %lu, ack = %lu\n", sequenceNumber, acknowledgmentNumber));
+	if (fIPService == NULL)
+		return B_NO_INIT;
+	if (buffer == NULL)
+		return B_BAD_VALUE;
+
+	tcp_header header;
+	ChainBuffer headerBuffer(&header, sizeof(header), buffer);
+	memset(&header, 0, sizeof(header));
+	header.source = htons(sourcePort);
+	header.destination = htons(destinationPort);
+	header.seqNumber = htonl(sequenceNumber);
+	header.ackNumber = htonl(acknowledgmentNumber);
+	header.dataOffset = 5;
+	header.ack = (flags & TCP_ACK) != 0;
+	header.syn = (flags & TCP_SYN) != 0;
+	header.fin = (flags & TCP_FIN) != 0;
+	header.rst = (flags & TCP_RST) != 0;
+	header.window = 0xffff;
+
+	header.checksum = 0;
+	header.checksum = htons(_ChecksumBuffer(&headerBuffer,
+		fIPService->IPAddress(), destinationAddress,
+		headerBuffer.TotalSize()));
+
+	return fIPService->Send(destinationAddress, IPPROTO_TCP, &headerBuffer);
+}
+
+
+void
+TCPService::ProcessIncomingPackets()
+{
+	if (fIPService != NULL)
+		fIPService->ProcessIncomingPackets();
+}
+
+
+status_t
+TCPService::BindSocket(TCPSocket* socket)
+{
+	if (socket == NULL)
+		return B_BAD_VALUE;
+
+	if (_FindSocket(socket->Address(), socket->Port()))
+		return EADDRINUSE;
+
+	return fSockets.Add(socket);
+}
+
+
+void
+TCPService::UnbindSocket(TCPSocket* socket)
+{
+	fSockets.Remove(socket);
+}
+
+
+uint16
+TCPService::_ChecksumBuffer(ChainBuffer* buffer, ip_addr_t source,
+	ip_addr_t destination, uint16 length)
+{
+	struct pseudo_header {
+		ip_addr_t	source;
+		ip_addr_t	destination;
+		uint8		pad;
+		uint8		protocol;
+		uint16		length;
+	} __attribute__ ((__packed__));
+	pseudo_header header = {
+		htonl(source),
+		htonl(destination),
+		0,
+		IPPROTO_TCP,
+		htons(length)
+	};
+
+	ChainBuffer headerBuffer(&header, sizeof(header), buffer);
+	uint16 checksum = ip_checksum(&headerBuffer);
+	headerBuffer.DetachNext();
+	return checksum;
+}
+
+
+uint16
+TCPService::_ChecksumData(const void* data, uint16 length, ip_addr_t source,
+	ip_addr_t destination)
+{
+	ChainBuffer buffer((void*)data, length);
+	return _ChecksumBuffer(&buffer, source, destination, length);
+}
+
+
+TCPSocket*
+TCPService::_FindSocket(ip_addr_t address, uint16 port)
+{
+	for (int i = 0; i < fSockets.Count(); i++) {
+		TCPSocket* socket = fSockets.ElementAt(i);
+		if ((address == INADDR_ANY || socket->Address() == INADDR_ANY
+					|| socket->Address() == address)
+				&& socket->Port() == port) {
+			return socket;
+		}
+	}
+	return NULL;
+}
