/* flaneth - flash and ethernet
   Copyright (C) 2007-2012 Stefan Schuermans <stefan@blinkenarea.org>
   Copyleft: GNU public license V2 - http://www.gnu.org/copyleft/gpl.html
   a BlinkenArea project - http://www.blinkenarea.org/ */

#ifndef INC_tcp
#define INC_tcp

#include "ethernet.h"
#include "ip.h"

// header of a TCP packet
struct TcpHeader {
  unsigned int SrcPort;
  unsigned int DestPort;
  unsigned long SeqNo;
  unsigned long AckNo;
  unsigned int Ofs_Flags;
  unsigned int WndSz;
  unsigned int Chk;
  unsigned int UrgentPtr;
};

// a TCP packet
struct TcpPacket {
  struct EthernetHeader EthHdr;
  struct IpHeader IpHdr;
  struct TcpHeader TcpHdr;
};

// TCP notify functions
struct TcpNotify {
  // called when connection is established
  void (*Connect) (unsigned char ConnNo);
  // called when connection is closed / reset
  // (after this, the connection number may not be used any more)
  void (*Close) (unsigned char ConnNo);
  // called when sending data is possible
  // (return length of available data, 0xFFFF to close connection)
  unsigned short (*Send) (unsigned char ConnNo, unsigned long Pos,
                          unsigned char *pBuffer, unsigned short MaxLen);
  // called when data was sent and ACKed
  void (*Sent) (unsigned char ConnNo, unsigned long Pos);
  // called when data was received, must return new window size (not smaller
  // than curWnd)
  unsigned short (*Received) (unsigned char ConnNo, unsigned long Pos,
                              unsigned char *pBuffer, unsigned short Len,
                              unsigned short curWnd);
};

// a TCP connection (member names according to RFC793)
// BUG: missing urgent pointers, which must be supported according to RFC793
// but urgent data is not used in protocols we use, so leave this out here to 
// save time and memory
#define TCP_CLOSED 0
#define TCP_LISTEN 1
#define TCP_SYN_SENT 2
#define TCP_SYN_RCVD 3
#define TCP_ESTAB 4
#define TCP_FIN_WAIT_1 5
#define TCP_FIN_WAIT_2 6
#define TCP_CLOSE_WAIT 7
#define TCP_LAST_ACK 8
#define TCP_CLOSING 9
#define TCP_TIME_WAIT 10
struct TcpConnection {
  unsigned char RemoteIp[4];
  unsigned short LocalPort, RemotePort;
  unsigned char State;  // one of TCP_*
  unsigned long SndUna; // send unacknowledged
  unsigned long SndNxt; // send next
  unsigned short SndWnd;        // send window
  unsigned long SndWl1; // segment sequence number used for last window
                        // update
  unsigned long SndWl2; // segment acknowledgment number used for last window 
                        // update
  unsigned long Iss;    // initial send sequence number
  unsigned long RcvNxt; // receive next
  unsigned short RcvWnd;        // receive window
  unsigned long Irs;    // initial receive sequence number
  unsigned short Mss;   // maximum segment size
  unsigned char Ticks;  // retransmission and time-wait timer (time since
                        // last packet sent or received in 200ms steps)
  unsigned char Timeout;        // timeout timer (time since last data was
                                // sent or received)
  unsigned char LifeTime;       // lifetime timer (time since begin of
                                // connection)
  struct TcpNotify *Notify;     // notification functions
};

// initialize
extern void TcpInit(void);

// tick procedure - call every 200ms
extern void TcpTick200(void);

// process a received TCP packet
extern void TcpRecv(unsigned char *pData, unsigned short Length);

// open a TCP connection
// must not be called from a TCP notification function
// returns the connection number of the new connection of 0xFF in case of
// error
extern unsigned char TcpOpen(unsigned char *remoteIp,
                             unsigned short remotePort,
                             unsigned short initialWnd,
                             struct TcpNotify *Notify);

// close a TCP connection
// must not be called from a TCP notification function
extern void TcpClose(unsigned char connNo);

// request sending on a TCP connection
// must not be called from a TCP notification function
// this makes the send notification to be called if possible
extern void TcpSend(unsigned char connNo);

#endif // #ifdef INC_tcp
