Ticket #5240: tcp-draft-01.diff

File tcp-draft-01.diff, 22.6 KB (added by andreasf, 14 years ago)

draft patch

  • headers/private/kernel/boot/net/NetDefs.h

    diff --git a/headers/private/kernel/boot/net/NetDefs.h b/headers/private/kernel/boot/net/NetDefs.h
    index d190ff6..041e1ee 100644
    a b  
    11/*
    22 * Copyright 2005, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
     3 * Copyright 2010, Andreas Faerber <andreas.faerber@web.de>
    34 * All rights reserved. Distributed under the terms of the MIT License.
    45 */
    56
    struct ip_header {  
    157158#define IP_DEFAULT_TIME_TO_LIVE     64      /* default ttl, from RFC 1340 */
    158159
    159160// IP protocols
     161#define IPPROTO_TCP                 6
    160162#define IPPROTO_UDP                 17
    161163
    162164
    struct udp_header  
    174176} __attribute__ ((__packed__));
    175177
    176178
     179// Transmission Control Protocol (TCP)
     180
     181// TCP header (RFC 793, RFC 3168)
     182struct tcp_header
     183{
     184    uint16 source;          // source port
     185    uint16 destination;     // destination port
     186    uint32 seqNumber;       // sequence number
     187    uint32 ackNumber;       // acknowledgment number
     188#if __BYTE_ORDER == __BIG_ENDIAN
     189    uint8 dataOffset:4;     // data offset
     190    uint8 reserved:4;       // reserved
     191#elif __BYTE_ORDER == __LITTLE_ENDIAN
     192    uint8 reserved:4;       // reserved
     193    uint8 dataOffset:4;     // data offset
     194#endif
     195#if __BYTE_ORDER == __BIG_ENDIAN
     196    bool cwr:1;
     197    bool ece:1;
     198    bool urg:1;
     199    bool ack:1;
     200    bool psh:1;
     201    bool rst:1;
     202    bool syn:1;
     203    bool fin:1;
     204#elif __BYTE_ORDER == __LITTLE_ENDIAN
     205    bool fin:1;
     206    bool syn:1;
     207    bool rst:1;
     208    bool psh:1;
     209    bool ack:1;
     210    bool urg:1;
     211    bool ece:1;
     212    bool cwr:1;
     213#endif
     214    uint16 window;          // window size
     215    uint16 checksum;        // checksum
     216    uint16 urgentPointer;   // urgent pointer
     217} __attribute__ ((__packed__));
     218
    177219// #pragma mark -
    178220
    179221// NetService
    extern const char *const kEthernetServiceName;  
    183225extern const char *const kARPServiceName;
    184226extern const char *const kIPServiceName;
    185227extern const char *const kUDPServiceName;
     228extern const char *const kTCPServiceName;
    186229
    187230class NetService {
    188231public:
  • headers/private/kernel/boot/net/NetStack.h

    diff --git a/headers/private/kernel/boot/net/NetStack.h b/headers/private/kernel/boot/net/NetStack.h
    index e2baeaa..f148732 100644
    a b class EthernetService;  
    1313class ARPService;
    1414class IPService;
    1515class UDPService;
     16class TCPService;
    1617
    1718
    1819class NetStack {
    public:  
    3435    ARPService *GetARPService() const           { return fARPService; }
    3536    IPService *GetIPService() const             { return fIPService; }
    3637    UDPService *GetUDPService() const           { return fUDPService; }
     38    TCPService *GetTCPService() const           { return fTCPService; }
    3739
    3840private:
    3941    static NetStack     *sNetStack;
    private:  
    4345    ARPService          *fARPService;
    4446    IPService           *fIPService;
    4547    UDPService          *fUDPService;
     48    TCPService          *fTCPService;
    4649};
    4750
    4851
  • new file headers/private/kernel/boot/net/TCP.h

    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
    - +  
     1/*
     2 * Copyright 2010 Andreas Faerber <andreas.faerber@web.de>
     3 * All rights reserved. Distributed under the terms of the MIT License.
     4 */
     5
     6#ifndef BOOT_NET_TCP_H
     7#define BOOT_NET_TCP_H
     8
     9#include <boot/net/IP.h>
     10
     11
     12class TCPPacket {
     13public:
     14    TCPPacket();
     15    ~TCPPacket();
     16
     17    status_t SetTo(const void* data, size_t size, ip_addr_t sourceAddress,
     18        uint16 sourcePort, ip_addr_t destinationAddress,
     19        uint16 destinationPort, uint32 sequenceNumber,
     20        uint32 acknowledgmentNumber, uint8 flags);
     21
     22    ip_addr_t SourceAddress() const;
     23    ip_addr_t DestinationAddress() const;
     24    uint16 SourcePort() const;
     25    uint16 DestinationPort() const;
     26    uint32 SequenceNumber() const;
     27    uint32 AcknowledgmentNumber() const;
     28    const void* Data() const { return fData; }
     29    size_t DataSize() const { return fSize; }
     30    uint8 Flags() const { return fFlags; }
     31
     32    TCPPacket* Next() const;
     33    void SetNext(TCPPacket* packet);
     34
     35private:
     36    ip_addr_t   fSourceAddress;
     37    ip_addr_t   fDestinationAddress;
     38    uint16      fSourcePort;
     39    uint16      fDestinationPort;
     40    uint32      fSequenceNumber;
     41    uint32      fAcknowledgmentNumber;
     42    void*       fData;
     43    size_t      fSize;
     44    uint8       fFlags;
     45    TCPPacket*  fNext;
     46};
     47
     48#define TCP_SYN     1
     49#define TCP_ACK     2
     50#define TCP_FIN     4
     51#define TCP_RST     8
     52
     53class TCPService;
     54
     55enum TCPSocketState {
     56    TCP_SOCKET_STATE_INITIAL,
     57    TCP_SOCKET_STATE_SYN_SENT,
     58    TCP_SOCKET_STATE_SYN_RECEIVED,
     59    TCP_SOCKET_STATE_OPEN,
     60    TCP_SOCKET_STATE_FIN_SENT,
     61    TCP_SOCKET_STATE_CLOSED
     62};
     63
     64class TCPSocket {
     65public:
     66    TCPSocket();
     67    ~TCPSocket();
     68
     69    ip_addr_t Address() const   { return fAddress; }
     70    uint16 Port() const         { return fPort; }
     71
     72    status_t Connect(ip_addr_t address, uint16 port);
     73    status_t Close();
     74    status_t Receive(TCPPacket** packet, bigtime_t timeout = 0);
     75
     76    void Acknowledge(uint32 number);
     77    void ProcessPacket(TCPPacket* packet);
     78    TCPPacket* DequeuePacket();
     79    TCPPacket* PopPacket();
     80
     81private:
     82    status_t _Send(TCPPacket* packet);
     83    status_t _ResendQueue();
     84    void _EnqueueOutgoingPacket(TCPPacket* packet);
     85    status_t _WaitForState(TCPSocketState state, bigtime_t timeout = 0);
     86    status_t _Ack();
     87
     88    TCPService* fTCPService;
     89    ip_addr_t   fAddress;
     90    uint16      fPort;
     91    ip_addr_t   fRemoteAddress;
     92    uint16      fRemotePort;
     93    uint32      fSequenceNumber;
     94    uint32      fAcknowledgeNumber;
     95    uint32      fNextPacket;
     96    TCPPacket*  fFirstPacket;
     97    TCPPacket*  fLastPacket;
     98    TCPPacket*  fFirstSentPacket;
     99    TCPPacket*  fLastSentPacket;
     100    TCPSocketState fState;
     101    TCPSocketState fRemoteState;
     102};
     103
     104class TCPService : public IPSubService {
     105public:
     106    TCPService(IPService* ipService);
     107    virtual ~TCPService();
     108
     109    status_t Init();
     110
     111    virtual uint8 IPProtocol() const;
     112
     113    virtual void HandleIPPacket(IPService* ipService, ip_addr_t sourceIP,
     114        ip_addr_t destinationIP, const void* data, size_t size);
     115
     116    status_t Send(uint16 sourcePort, ip_addr_t destinationAddress,
     117        uint16 destinationPort, uint32 sequenceNumber,
     118        uint32 acknowledgmentNumber, uint8 flags, ChainBuffer* buffer);
     119
     120    void ProcessIncomingPackets();
     121
     122    status_t BindSocket(TCPSocket* socket);
     123    void UnbindSocket(TCPSocket* socket);
     124
     125private:
     126    uint16 _ChecksumBuffer(ChainBuffer* buffer, ip_addr_t source,
     127        ip_addr_t destination, uint16 length);
     128    uint16 _ChecksumData(const void* data, uint16 length, ip_addr_t source,
     129        ip_addr_t destination);
     130
     131    TCPSocket* _FindSocket(ip_addr_t address, uint16 port);
     132
     133    IPService*          fIPService;
     134    Vector<TCPSocket*>  fSockets;
     135};
     136
     137#endif
  • src/system/boot/loader/net/Jamfile

    diff --git a/src/system/boot/loader/net/Jamfile b/src/system/boot/loader/net/Jamfile
    index 8555a7d..8a8245f 100644
    a b KernelStaticLibrary boot_net :  
    1313    NetStack.cpp
    1414    RemoteDisk.cpp
    1515    UDP.cpp
     16    TCP.cpp
    1617
    1718    : -fno-pic
    1819;
  • src/system/boot/loader/net/NetDefs.cpp

    diff --git a/src/system/boot/loader/net/NetDefs.cpp b/src/system/boot/loader/net/NetDefs.cpp
    index 009e4c0..19b7681 100644
    a b const char *const kEthernetServiceName = "ethernet";  
    1616const char *const kARPServiceName = "arp";
    1717const char *const kIPServiceName = "ip";
    1818const char *const kUDPServiceName = "udp";
     19const char *const kTCPServiceName = "tcp";
    1920
    2021
    2122// constructor
  • src/system/boot/loader/net/NetStack.cpp

    diff --git a/src/system/boot/loader/net/NetStack.cpp b/src/system/boot/loader/net/NetStack.cpp
    index 7db3de0..0154997 100644
    a b  
    1313#include <boot/net/Ethernet.h>
    1414#include <boot/net/IP.h>
    1515#include <boot/net/UDP.h>
     16#include <boot/net/TCP.h>
    1617
    1718
    1819// sNetStack
    NetStack::NetStack()  
    2425        fEthernetService(NULL),
    2526        fARPService(NULL),
    2627        fIPService(NULL),
    27         fUDPService(NULL)
     28        fUDPService(NULL),
     29        fTCPService(NULL)
    2830{
    2931}
    3032
    3133// destructor
    3234NetStack::~NetStack()
    3335{
     36    delete fTCPService;
    3437    delete fUDPService;
    3538    delete fIPService;
    3639    delete fARPService;
    NetStack::Init()  
    7376    if (error != B_OK)
    7477        return error;
    7578
     79    // TCP service
     80    fTCPService = new(nothrow) TCPService(fIPService);
     81    if (fTCPService == NULL)
     82        return B_NO_MEMORY;
     83    error = fTCPService->Init();
     84    if (error != B_OK)
     85        return error;
     86
    7687    return B_OK;
    7788}
    7889
  • new file src/system/boot/loader/net/TCP.cpp

    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
    - +  
     1/*
     2 * Copyright 2010 Andreas Faerber <andreas.faerber@web.de>
     3 * All rights reserved. Distributed under the terms of the MIT License.
     4 */
     5
     6#include <boot/net/TCP.h>
     7
     8#include <stdio.h>
     9#include <KernelExport.h>
     10
     11#include <boot/net/ChainBuffer.h>
     12#include <boot/net/NetStack.h>
     13
     14
     15//#define TRACE_TCP
     16#ifdef TRACE_TCP
     17#   define TRACE(x) dprintf x
     18#else
     19#   define TRACE(x) ;
     20#endif
     21
     22
     23TCPPacket::TCPPacket()
     24    :
     25    fNext(NULL)
     26{
     27}
     28
     29
     30TCPPacket::~TCPPacket()
     31{
     32}
     33
     34
     35status_t
     36TCPPacket::SetTo(const void* data, size_t size, ip_addr_t sourceAddress,
     37    uint16 sourcePort, ip_addr_t destinationAddress, uint16 destinationPort,
     38    uint32 sequenceNumber, uint32 acknowledgmentNumber, uint8 flags)
     39{
     40    if (data == NULL && size > 0)
     41        return B_BAD_VALUE;
     42
     43    if (size > 0) {
     44        fData = malloc(size);
     45        if (fData == NULL)
     46            return B_NO_MEMORY;
     47        memcpy(fData, data, size);
     48    } else {
     49        fData = NULL;
     50    }
     51
     52    fSize = size;
     53    fSourceAddress = sourceAddress;
     54    fSourcePort = sourcePort;
     55    fDestinationAddress = destinationAddress;
     56    fDestinationPort = destinationPort;
     57    fSequenceNumber = sequenceNumber;
     58    fAcknowledgmentNumber = acknowledgmentNumber;
     59    fFlags = flags;
     60
     61    return B_OK;
     62}
     63
     64
     65ip_addr_t
     66TCPPacket::SourceAddress() const
     67{
     68    return fSourceAddress;
     69}
     70
     71
     72ip_addr_t
     73TCPPacket::DestinationAddress() const
     74{
     75    return fDestinationAddress;
     76}
     77
     78
     79uint16
     80TCPPacket::SourcePort() const
     81{
     82    return fSourcePort;
     83}
     84
     85
     86uint16
     87TCPPacket::DestinationPort() const
     88{
     89    return fDestinationPort;
     90}
     91
     92
     93uint32
     94TCPPacket::SequenceNumber() const
     95{
     96    return fSequenceNumber;
     97}
     98
     99
     100uint32
     101TCPPacket::AcknowledgmentNumber() const
     102{
     103    return fAcknowledgmentNumber;
     104}
     105
     106
     107TCPPacket*
     108TCPPacket::Next() const
     109{
     110    return fNext;
     111}
     112
     113
     114void
     115TCPPacket::SetNext(TCPPacket* packet)
     116{
     117    fNext = packet;
     118}
     119
     120
     121
     122
     123TCPSocket::TCPSocket()
     124    :
     125    fTCPService(NetStack::Default()->GetTCPService()),
     126    fAddress(INADDR_ANY),
     127    fPort(0),
     128    fSequenceNumber(0),
     129    fFirstPacket(NULL),
     130    fLastPacket(NULL),
     131    fFirstSentPacket(NULL),
     132    fLastSentPacket(NULL),
     133    fState(TCP_SOCKET_STATE_INITIAL),
     134    fRemoteState(TCP_SOCKET_STATE_INITIAL)
     135{
     136}
     137
     138
     139TCPSocket::~TCPSocket()
     140{
     141    if (fTCPService != NULL && fPort != 0)
     142        fTCPService->UnbindSocket(this);
     143}
     144
     145
     146status_t
     147TCPSocket::Connect(ip_addr_t address, uint16 port)
     148{
     149    fRemoteAddress = address;
     150    fRemotePort = port;
     151    TRACE(("time %llu\n", system_time()));
     152    fSequenceNumber = system_time();
     153    uint16 random = system_time();
     154    fPort = 0xC000 + (random & ~0xc000);
     155    fAcknowledgeNumber = 0;
     156    fNextPacket = 0;
     157
     158    status_t error = fTCPService->BindSocket(this);
     159    if (error != B_OK)
     160        return error;
     161
     162    // send SYN
     163    TCPPacket* packet = new(nothrow) TCPPacket();
     164    if (packet == NULL)
     165        return B_NO_MEMORY;
     166    error = packet->SetTo(NULL, 0, fAddress, fPort, address, port,
     167        fSequenceNumber, fAcknowledgeNumber, TCP_SYN);
     168    if (error != B_OK)
     169        return error;
     170    error = _Send(packet);
     171    if (error != B_OK)
     172        return error;
     173    fState = TCP_SOCKET_STATE_SYN_SENT;
     174    TRACE(("SYN sent\n"));
     175
     176    // receive SYN-ACK
     177    error = _WaitForState(TCP_SOCKET_STATE_OPEN, 1000000LL);
     178    if (error != B_OK) {
     179        TRACE(("no SYN-ACK received\n"));
     180        return error;
     181    }
     182    TRACE(("SYN-ACK received\n"));
     183
     184    return B_OK;
     185}
     186
     187
     188status_t
     189TCPSocket::Close()
     190{
     191    // send FIN
     192    TCPPacket* packet = new(nothrow) TCPPacket();
     193    if (packet == NULL)
     194        return B_NO_MEMORY;
     195    status_t error = packet->SetTo(NULL, 0, fAddress, fPort, fRemoteAddress, fRemotePort,
     196        fSequenceNumber, fAcknowledgeNumber, TCP_FIN | TCP_ACK);
     197    if (error != B_OK)
     198        return error;
     199    error = _Send(packet);
     200    if (error != B_OK)
     201        return error;
     202    fState = TCP_SOCKET_STATE_FIN_SENT;
     203    TRACE(("FIN sent\n"));
     204
     205    error = _WaitForState(TCP_SOCKET_STATE_CLOSED, 1000000LL);
     206    if (error != B_OK)
     207        return error;
     208
     209    return B_OK;
     210}
     211
     212
     213status_t
     214TCPSocket::Receive(TCPPacket** _packet, bigtime_t timeout)
     215{
     216    if (fTCPService == NULL)
     217        return B_NO_INIT;
     218    if (_packet == NULL)
     219        return B_BAD_VALUE;
     220    bigtime_t startTime = system_time();
     221    do {
     222        fTCPService->ProcessIncomingPackets();
     223        TCPPacket* packet = DequeuePacket();
     224        if (packet != NULL) {
     225            *_packet = packet;
     226            return B_OK;
     227        }
     228        _ResendQueue();
     229    } while (system_time() - startTime < timeout);
     230    return timeout == 0 ? B_WOULD_BLOCK : B_TIMED_OUT;
     231}
     232
     233
     234void
     235TCPSocket::Acknowledge(uint32 number)
     236{
     237    TRACE(("TCPSocket::Acknowledge(): %lu\n", number));
     238    // dequeue packets
     239    for (TCPPacket* packet = fFirstSentPacket; packet != NULL;
     240            packet = fFirstSentPacket) {
     241        if (packet->SequenceNumber() > number ||
     242                (packet->SequenceNumber() == number && packet->DataSize() > 0))
     243            return;
     244        fFirstSentPacket = packet->Next();
     245        delete packet;
     246    }
     247    fLastSentPacket = NULL;
     248}
     249
     250
     251void
     252TCPSocket::ProcessPacket(TCPPacket* packet)
     253{
     254    TRACE(("TCPSocket::ProcessPacket()\n"));
     255
     256    if ((packet->Flags() & TCP_FIN) != 0) {
     257        fRemoteState = TCP_SOCKET_STATE_FIN_SENT;
     258        TRACE(("FIN received\n"));
     259        _Ack();
     260    }
     261
     262    if (fState == TCP_SOCKET_STATE_SYN_SENT) {
     263        if ((packet->Flags() & TCP_SYN) != 0
     264                && (packet->Flags() & TCP_ACK) != 0) {
     265            fNextPacket = fAcknowledgeNumber = packet->SequenceNumber() + 1;
     266            fRemoteState = TCP_SOCKET_STATE_SYN_SENT;
     267            delete packet;
     268            _Ack();
     269            fState = fRemoteState = TCP_SOCKET_STATE_OPEN;
     270            return;
     271        }
     272    } else if (fState == TCP_SOCKET_STATE_OPEN) {
     273    } else if (fState == TCP_SOCKET_STATE_FIN_SENT) {
     274        if ((packet->Flags() & TCP_ACK) != 0) {
     275            TRACE(("FIN-ACK received\n"));
     276            if (fRemoteState == TCP_SOCKET_STATE_FIN_SENT)
     277                fState = TCP_SOCKET_STATE_CLOSED;
     278        }
     279    }
     280
     281    /*if (fLastPacket == NULL) {
     282        // no packets enqueued
     283        packet->SetNext(NULL);
     284        fFirstPacket = fLastPacket = packet;
     285    } else if (fLastPacket->SequenceNumber() < packet->SequenceNumber()) {
     286        // enqueue in back
     287        fLastPacket->SetNext(packet);
     288        fLastPacket = packet;
     289    } else if (fFirstPacket->SequenceNumber() > packet->SequenceNumber()) {
     290        // enqueue in front
     291        packet->SetNext(fFirstPacket);
     292        fFirstPacket = packet;
     293    } else {
     294        // enqueue in middle
     295        for (TCPPacket* queuedPacket = fFirstPacket; queuedPacket != NULL;
     296                queuedPacket = queuedPacket->Next()) {
     297            if (queuedPacket->SequenceNumber() == packet->SequenceNumber()) {
     298                TRACE(("TCPSocket::EnqueuePacket(): TCP packet dropped\n"));
     299                // we may be waiting for a previous packet
     300                return;
     301            }
     302            if (queuedPacket->Next()->SequenceNumber() > packet->SequenceNumber()) {
     303                packet->SetNext(queuedPacket->Next());
     304                queuedPacket->SetNext(packet);
     305                break;
     306            }
     307        }
     308    }*/
     309}
     310
     311
     312TCPPacket*
     313TCPSocket::DequeuePacket()
     314{
     315    //TRACE(("TCPSocket::DequeuePacket()\n"));
     316    if (fFirstPacket == NULL)
     317        return NULL;
     318
     319    if (fFirstPacket->SequenceNumber() == fNextPacket)
     320        return PopPacket();
     321
     322    for (TCPPacket* packet = fFirstPacket;
     323            packet != NULL && packet->Next() != NULL;
     324            packet = packet->Next()) {
     325        if (packet->Next()->SequenceNumber() == fNextPacket) {
     326            TCPPacket* nextPacket = packet->Next();
     327            packet->SetNext(nextPacket->Next());
     328            if (fLastPacket == nextPacket)
     329                fLastPacket = packet;
     330            fNextPacket += nextPacket->DataSize();
     331            return nextPacket;
     332        }
     333    }
     334    return NULL;
     335}
     336
     337
     338TCPPacket*
     339TCPSocket::PopPacket()
     340{
     341    //TRACE(("TCPSocket::PopPacket()\n"));
     342    if (fFirstPacket == NULL)
     343        return NULL;
     344
     345    TCPPacket* packet = fFirstPacket;
     346    fFirstPacket = packet->Next();
     347    if (fFirstPacket == NULL)
     348        fLastPacket = NULL;
     349    packet->SetNext(NULL);
     350    return packet;
     351}
     352
     353
     354status_t
     355TCPSocket::_Send(TCPPacket* packet)
     356{
     357    ChainBuffer buffer((void*)packet->Data(), packet->DataSize());
     358    status_t error = fTCPService->Send(fPort, fRemoteAddress, fRemotePort,
     359        packet->SequenceNumber(), fAcknowledgeNumber, packet->Flags(),
     360        &buffer);
     361    if (error != B_OK)
     362        return error;
     363    fSequenceNumber += packet->DataSize();
     364    _EnqueueOutgoingPacket(packet);
     365    return B_OK;
     366}
     367
     368
     369status_t
     370TCPSocket::_ResendQueue()
     371{
     372    TRACE(("TCPSocket::_ResendQueue()\n"));
     373    for (TCPPacket* packet = fFirstSentPacket; packet != NULL;
     374            packet = packet->Next()) {
     375        ChainBuffer buffer((void*)packet->Data(), packet->DataSize());
     376        status_t error = fTCPService->Send(fPort, fRemoteAddress, fRemotePort,
     377            packet->SequenceNumber(), fAcknowledgeNumber, packet->Flags(),
     378            &buffer);
     379        if (error != B_OK)
     380            return error;
     381    }
     382    return B_OK;
     383}
     384
     385
     386void
     387TCPSocket::_EnqueueOutgoingPacket(TCPPacket* packet)
     388{
     389    if (fLastSentPacket != NULL) {
     390        fLastSentPacket->SetNext(packet);
     391        fLastSentPacket = packet;
     392    } else {
     393        fFirstSentPacket = fLastSentPacket = packet;
     394    }
     395}
     396
     397
     398status_t
     399TCPSocket::_Ack()
     400{
     401    TCPPacket* packet = new(nothrow) TCPPacket();
     402    if (packet == NULL)
     403        return B_NO_MEMORY;
     404    status_t error = packet->SetTo(NULL, 0, fAddress, fPort, fRemoteAddress,
     405        fRemotePort, fSequenceNumber, fAcknowledgeNumber, TCP_ACK);
     406    if (error != B_OK)
     407        return error;
     408    error = _Send(packet);
     409    if (error != B_OK)
     410        return error;
     411    return B_OK;
     412}
     413
     414
     415status_t
     416TCPSocket::_WaitForState(TCPSocketState state, bigtime_t timeout)
     417{
     418    if (fTCPService == NULL)
     419        return B_NO_INIT;
     420
     421    bigtime_t startTime = system_time();
     422    do {
     423        fTCPService->ProcessIncomingPackets();
     424        if (fState == state)
     425            return B_OK;
     426    } while (system_time() - startTime < timeout);
     427    return timeout == 0 ? B_WOULD_BLOCK : B_TIMED_OUT;
     428}
     429
     430
     431
     432
     433TCPService::TCPService(IPService* ipService)
     434    :
     435    IPSubService(kTCPServiceName),
     436    fIPService(ipService)
     437{
     438}
     439
     440
     441TCPService::~TCPService()
     442{
     443    if (fIPService != NULL)
     444        fIPService->UnregisterIPSubService(this);
     445}
     446
     447
     448status_t
     449TCPService::Init()
     450{
     451    if (fIPService == NULL)
     452        return B_BAD_VALUE;
     453    if (!fIPService->RegisterIPSubService(this))
     454        return B_NO_MEMORY;
     455    return B_OK;
     456}
     457
     458
     459uint8
     460TCPService::IPProtocol() const
     461{
     462    return IPPROTO_TCP;
     463}
     464
     465
     466void
     467TCPService::HandleIPPacket(IPService* ipService, ip_addr_t sourceIP,
     468    ip_addr_t destinationIP, const void* data, size_t size)
     469{
     470    TRACE(("TCPService::HandleIPPacket(): source = %08lx, destination = %08lx, "
     471        "%lu - %lu bytes\n", sourceIP, destinationIP, size, sizeof(tcp_header)));
     472
     473    if (data == NULL || size < sizeof(tcp_header))
     474        return;
     475
     476    const tcp_header* header = (const tcp_header*)data;
     477    uint16 source = ntohs(header->source);
     478    uint16 destination = ntohs(header->destination);
     479    uint32 sequenceNumber = ntohl(header->seqNumber);
     480    uint32 ackedNumber = ntohl(header->ackNumber);
     481    uint8 flags = 0;
     482    if (header->syn)
     483        flags |= TCP_SYN;
     484    if (header->ack)
     485        flags |= TCP_ACK;
     486    if (header->fin)
     487        flags |= TCP_FIN;
     488    if (header->rst)
     489        flags |= TCP_RST;
     490    TRACE(("\tsource = %u, dest = %u, seq = %lu, ack = %lu, dataOffset = %u, flags %s %s %s %s\n",
     491        source, destination, sequenceNumber, ackedNumber, header->dataOffset,
     492        header->ack ? "ACK" : "", header->syn ? "SYN" : "", header->fin ? "FIN" : "", header->rst ? "RST" : ""));
     493    if (header->dataOffset > 5) {
     494        uint8* option = (uint8*)data + sizeof(tcp_header);
     495        while ((uint32*)option < (uint32*)data + header->dataOffset) {
     496            uint8 optionKind = option[0];
     497            uint8 optionLength = 1;
     498            if (optionKind > 1)
     499                optionLength = option[1];
     500            TRACE(("\tTCP option kind %u, length %u\n", optionKind, optionLength));
     501            option += optionLength;
     502        }
     503    }
     504
     505    uint16 chksum = _ChecksumData(data, size, sourceIP, destinationIP);
     506    if (chksum != 0) {
     507        TRACE(("TCPService::HandleIPPacket(): invalid checksum (%04x)\n", header->checksum));
     508        //return;
     509    }
     510
     511    TCPSocket* socket = _FindSocket(destinationIP, destination);
     512    if (socket == NULL) {
     513        //TODO if SYN, answer with RST?
     514        return;
     515    }
     516
     517    if (header->ack) {
     518        socket->Acknowledge(ackedNumber);
     519    }
     520
     521    TCPPacket* packet = new(nothrow) TCPPacket();
     522    if (packet == NULL)
     523        return;
     524    status_t error = packet->SetTo((uint32*)data + header->dataOffset,
     525        size - header->dataOffset * 4, sourceIP, source, destinationIP,
     526        destination, sequenceNumber, ackedNumber, flags);
     527    if (error == B_OK)
     528        socket->ProcessPacket(packet);
     529    else
     530        delete packet;
     531}
     532
     533
     534status_t
     535TCPService::Send(uint16 sourcePort, ip_addr_t destinationAddress,
     536    uint16 destinationPort, uint32 sequenceNumber,
     537    uint32 acknowledgmentNumber, uint8 flags, ChainBuffer* buffer)
     538{
     539    TRACE(("TCPService::Send(): seq = %lu, ack = %lu\n", sequenceNumber, acknowledgmentNumber));
     540    if (fIPService == NULL)
     541        return B_NO_INIT;
     542    if (buffer == NULL)
     543        return B_BAD_VALUE;
     544
     545    tcp_header header;
     546    ChainBuffer headerBuffer(&header, sizeof(header), buffer);
     547    memset(&header, 0, sizeof(header));
     548    header.source = htons(sourcePort);
     549    header.destination = htons(destinationPort);
     550    header.seqNumber = htonl(sequenceNumber);
     551    header.ackNumber = htonl(acknowledgmentNumber);
     552    header.dataOffset = 5;
     553    header.ack = (flags & TCP_ACK) != 0;
     554    header.syn = (flags & TCP_SYN) != 0;
     555    header.fin = (flags & TCP_FIN) != 0;
     556    header.rst = (flags & TCP_RST) != 0;
     557    header.window = 0xffff;
     558
     559    header.checksum = 0;
     560    header.checksum = htons(_ChecksumBuffer(&headerBuffer,
     561        fIPService->IPAddress(), destinationAddress,
     562        headerBuffer.TotalSize()));
     563
     564    return fIPService->Send(destinationAddress, IPPROTO_TCP, &headerBuffer);
     565}
     566
     567
     568void
     569TCPService::ProcessIncomingPackets()
     570{
     571    if (fIPService != NULL)
     572        fIPService->ProcessIncomingPackets();
     573}
     574
     575
     576status_t
     577TCPService::BindSocket(TCPSocket* socket)
     578{
     579    if (socket == NULL)
     580        return B_BAD_VALUE;
     581
     582    if (_FindSocket(socket->Address(), socket->Port()))
     583        return EADDRINUSE;
     584
     585    return fSockets.Add(socket);
     586}
     587
     588
     589void
     590TCPService::UnbindSocket(TCPSocket* socket)
     591{
     592    fSockets.Remove(socket);
     593}
     594
     595
     596uint16
     597TCPService::_ChecksumBuffer(ChainBuffer* buffer, ip_addr_t source,
     598    ip_addr_t destination, uint16 length)
     599{
     600    struct pseudo_header {
     601        ip_addr_t   source;
     602        ip_addr_t   destination;
     603        uint8       pad;
     604        uint8       protocol;
     605        uint16      length;
     606    } __attribute__ ((__packed__));
     607    pseudo_header header = {
     608        htonl(source),
     609        htonl(destination),
     610        0,
     611        IPPROTO_TCP,
     612        htons(length)
     613    };
     614
     615    ChainBuffer headerBuffer(&header, sizeof(header), buffer);
     616    uint16 checksum = ip_checksum(&headerBuffer);
     617    headerBuffer.DetachNext();
     618    return checksum;
     619}
     620
     621
     622uint16
     623TCPService::_ChecksumData(const void* data, uint16 length, ip_addr_t source,
     624    ip_addr_t destination)
     625{
     626    ChainBuffer buffer((void*)data, length);
     627    return _ChecksumBuffer(&buffer, source, destination, length);
     628}
     629
     630
     631TCPSocket*
     632TCPService::_FindSocket(ip_addr_t address, uint16 port)
     633{
     634    for (int i = 0; i < fSockets.Count(); i++) {
     635        TCPSocket* socket = fSockets.ElementAt(i);
     636        if ((address == INADDR_ANY || socket->Address() == INADDR_ANY
     637                    || socket->Address() == address)
     638                && socket->Port() == port) {
     639            return socket;
     640        }
     641    }
     642    return NULL;
     643}