/*#######################################################################################
AVR Small Webserver 

Copyright (C) 2004 Ulrich Radig

#######################################################################################*/

#include "main.h"
#include "tcp.h" 
// #include "mmc.h"

//Globale Variablen
unsigned long Seq_counter;
unsigned long Ack_counter;

struct TCP_Socket tcpsockets[Max_TCP_Sockets]; //Feld mit Max_TCP_Sockets Sockets
struct TCP_Socket *tcp_socket;                 //Pointer auf einen TCP_Socket

PGM_P pointerold;

unsigned int sitecounter=0;
unsigned char password[16] = { 0 };

//############################################################################
//
void tcp_store (char *buffer)
//############################################################################
{
	//Variablen Fr die Routine
	unsigned int result16;
	
	//Pointer auf TCP_Header
	struct TCP_Header *tcp;
	tcp = (struct TCP_Header *)&buffer[TCP_OFFSET];
	
	//Store seq number to Seq_counter
	Seq_counter = (tcp->TCP_Seqnum[0] << 8)+tcp->TCP_Seqnum[1];
	Seq_counter = Seq_counter << 16;
	Seq_counter = Seq_counter +(unsigned int) ((tcp->TCP_Seqnum[2] << 8)
								+tcp->TCP_Seqnum[3]);

    //Store ack number to ACK_counter
	Ack_counter = (tcp->TCP_Acknum[0] << 8)+tcp->TCP_Acknum[1];
	Ack_counter = Ack_counter << 16;
	Ack_counter = Ack_counter +(unsigned int) ((tcp->TCP_Acknum[2] << 8)
								+tcp->TCP_Acknum[3]);

	//Calculate next seq number
	if ((tcp->TCP_HdrFlags[1] & FIN_FLAG) == 0)
		{
		result16 = (buffer[IP_PKTLEN]<<8) + buffer[IP_PKTLEN+1];
		result16 = result16 - ((buffer[IP_VERS_LEN] & 0x0F) << 2)
							- ((buffer[TCP_HDRFLAGS] & 0xF0) >>2);

		if ((buffer[TCP_HDRFLAGS+1]&SYN_FLAG) > 0
		&& result16 == 0)
			{
			result16 = 1;
			}
		Seq_counter =Seq_counter + result16;
		}
	return;
}

// check if an output pin is 1 or 0 and return "on" or "off" accordingly
void PortOnOff(unsigned char * StringPointer, unsigned char Mask)
{
	if (PORTD & Mask)
		memcpy(StringPointer, "on\0", 3);
	else
		memcpy(StringPointer, "off\0", 4);
	return;
}

// check if an input pin is 1 or 0 and return "off" or "on" accordingly (inverted!)
void PinOnOff(unsigned char * StringPointer, unsigned char Mask)
{
	if (PINC & Mask)
		memcpy(StringPointer, "off\0", 3);
	else
		memcpy(StringPointer, "on\0", 4);
	return;
}

//############################################################################
//
unsigned char tcp_add_data (PGM_P pointer,char *buffer,int *bufferlen)
//############################################################################
{
	//Variablen Fr die Routine
	unsigned int result16;
	unsigned char Data = 1;
	unsigned char Buffer_Full = 0;
	

	//Errechnet startpunkt der Daten im Tcp buffer
	//IP Headerl�ge + TCP Headerl�ge + Ethernetframe
	result16 = ((buffer[IP_VERS_LEN] & 0x0F) << 2) + 
				((buffer[TCP_HDRFLAGS] & 0xF0) >>2) + 14;

	for(;;)
		{
		Data = pgm_read_byte_near(pointer++);
		buffer[result16] = Data;
		result16++;
			//sind die daten l�ger als ein Ethernetbuffer dann abbruch
			if (result16 >  (MTU_SIZE - 1))
				{
				Buffer_Full = 1;
				//Speichern des Pointers
				pointerold = pointer;
				//Abbruch der Schleife
				break;
				}
				
			//% bedeutet es kommt evt. was besonderes!
			if (pgm_read_byte(pointer) =='%')
			{
				unsigned char OnOff[4] = "\0\0\0\0";
				// REL -> status of relay output
				if (strncmp_P("REL",(pointer+1),3) == 0)
					{
					pointer+=4;
					PortOnOff(OnOff, 0x10);
					}
				
				// OUT -> status of normal output
				if (strncmp_P("OUT",(pointer+1),3) == 0)
					{
					pointer+=4;
					PortOnOff(OnOff, 0x08);
					}
				
				// INP -> status of input
				if (strncmp_P("INP",(pointer+1),3) == 0)
					{
					pointer+=4;
					PinOnOff(OnOff, 0x20);
					}
				
				// Send string
				unsigned char i = 0;
				while (OnOff[i] != '\0')
					{
					buffer[result16++] = OnOff[i++];
					}
				
				//Abbruch wenn %END erreicht wurde
				if (strncmp_P("END",(pointer+1),3) == 0)
					{
					//Wait a short Time
					for(int a = 0;a<1000;a++){nop();};
					break;
					}
			}
		}
	TCP_New_Packtlen (buffer,bufferlen,result16);
	return(Buffer_Full);
}

//############################################################################
//
char tcp_add_datastring (char *pointer,char *buffer,int *bufferlen)
//############################################################################
{
	//Variablen Fr die Routine
	unsigned int result16;
	unsigned char Data = 1;
	unsigned char Buffer_Full = 0;
	

	//Errechnet startpunkt der Daten im Tcp buffer
	//IP Headerl�ge + TCP Headerl�ge + Ethernetframe
	result16 = ((buffer[IP_VERS_LEN] & 0x0F) << 2) + 
				((buffer[TCP_HDRFLAGS] & 0xF0) >>2) + 14;

	for(;;)
		{
		Data = *pointer++;
		buffer[result16] = Data;
		result16++;
			//sind die daten l�ger als ein Ethernetbuffer dann abbruch
			if (result16 >  (MTU_SIZE - 1))
				{
				Buffer_Full = 1;
				break;
				}
			//Abbruch wenn 0 erreicht wurde
			if (*pointer == 0)
				{
				//Wait a short Time
				for(int a = 0;a<1000;a++){nop();};
				break;
				}
		}
	TCP_New_Packtlen (buffer,bufferlen,result16);
	return(Buffer_Full);
}

//############################################################################
//
void TCP_New_Packtlen (char *buffer,int *bufferlen,unsigned int result16)	
//############################################################################
{	
	//addiert noch bufferheader zur neuen ethernetl�ge
	result16 = result16 + 4;
	*bufferlen = result16;
	//Errechnet die neue ip bufferl�ge aus Ethernet L�ge 
	//Ethernetframe - bufferheader
	result16 = result16 - 18;
	//schreibt neue IPl�ge ins buffer (ip_pktlenH)
	buffer[IP_PKTLEN] = ((result16 & 0xFF00) >> 8);
	//schreibt neue IPl�ge ins buffer (ip_pktlenL)
	buffer[IP_PKTLEN+1] = (result16 & 0x00FF);
	return;
}

//############################################################################
//
void tcp_make (char *buffer)
//############################################################################
{
	//Variablen Fr die Routine
	unsigned int result16;
	unsigned long result32 = 0x00000000;
	unsigned char DataH;
	unsigned char DataL;

	//Schreibt neuen seq und Ack Counter	
    buffer[TCP_ACKNUM] = (Seq_counter & 0xFF000000) >> 24;
    buffer[TCP_ACKNUM+1] = (Seq_counter & 0x00FF0000) >> 16;
    buffer[TCP_ACKNUM+2] = (Seq_counter & 0x0000FF00) >> 8;
    buffer[TCP_ACKNUM+3] = Seq_counter & 0x000000FF;

    buffer[TCP_SEQNUM] = (Ack_counter & 0xFF000000) >> 24;
    buffer[TCP_SEQNUM+1] = (Ack_counter & 0x00FF0000) >> 16;
    buffer[TCP_SEQNUM+2] = (Ack_counter & 0x0000FF00) >> 8;
    buffer[TCP_SEQNUM+3] = Ack_counter & 0x000000FF;

    //Tauscht den TCP source Port mit TCP destinations port yyyy >> XXXX

	DataH = buffer[TCP_SRCPORT];
    buffer[TCP_SRCPORT] = buffer[TCP_DESTPORT];
    buffer[TCP_DESTPORT] = DataH;

	DataL = buffer[TCP_SRCPORT+1];
    buffer[TCP_SRCPORT+1] = buffer[TCP_DESTPORT+1];
    buffer[TCP_DESTPORT+1] = DataL;

	//Erzeugt den IP Header	
    Make_IP_Header(buffer);

	//Berechnung der TCP Checksumme
	//Alle Daten im TCP Header werden addiert checksum wird deshalb
	//ersteinmal auf null gesetzt
	buffer[TCP_CHKSUM] = 0x00;
	buffer[TCP_CHKSUM+1] = 0x00;

	//Berechnet Headerl�ge und Addiert Pseudoheaderl�ge 2XIP = 8
	result16 = (buffer[IP_PKTLEN]<<8) + buffer[IP_PKTLEN+1] + 8;
	result16 = result16 - ((buffer[IP_VERS_LEN] & 0x0F) << 2);
	result32 = result16 - 2;

	//Pointer wird auf das erste buffer im IP Header gesetzt
	//Routine berechnet die Checksumme
	result16 = checksum (&buffer[IP_SRCADDR], result16, result32);

	//schreibt checksum ins buffer (INT H Byte)
	buffer[TCP_CHKSUM] = ((result16 & 0xFF00) >> 8);

	//schreibt checksum ins buffer (INT L Byte)
	buffer[TCP_CHKSUM+1] = (result16 & 0x00FF);

	//Habe Fertig!!
}

//############################################################################
//
void TCP_PORT_CLOSE (char *buffer,int *bufferlen)
//############################################################################
{
	//Speichert Sequenzcounter und Aknowledgecounter
	tcp_store(buffer);	
	//Setzen des FIN Flag
	buffer[TCP_HDRFLAGS+1] = ACK_FLAG | FIN_FLAG | PSH_FLAG;

	//Erzeugt ein TCP buffer 
	tcp_make(buffer);			
	//Sendet das erzeugte TCP buffer 
	Write_Ethernet_Frame (buffer,*bufferlen);
}

//############################################################################
//
int TCP_OPEN (char *buffer,int *bufferlen)
//############################################################################
{
 unsigned int tcp_srcport;

 tcp_srcport=(buffer[TCP_SRCPORT]<<8) + buffer[TCP_SRCPORT+1];

 unsigned char tcp_hdrflags1=buffer[TCP_HDRFLAGS+1];
 
	if ((tcp_hdrflags1 & SYN_FLAG) > 0 
	     && (tcp_hdrflags1 & (PSH_FLAG | ACK_FLAG)) == 0)
	{
		//Speichern des Socket
		for (unsigned char a=0;a<Max_TCP_Sockets;a++)
			{
			tcp_socket= &tcpsockets[a]; //Pointer auf tcpsockets[a] holen

			if (tcp_socket->Store == 0)
				{
				tcp_socket->Store = tcp_srcport;
				tcp_socket->Status = TCP_SOCKET_NOT_USE;
				break;
				}
			}
		//Speichert Sequenzcounter und Aknowledgecounter
		tcp_store(buffer);		
		//Setzen des Ack Flag
		buffer[TCP_HDRFLAGS+1] |= ACK_FLAG;
		//Erzeugt ein TCP buffer 
		tcp_make(buffer);			
		//Sendet das erzeugte TCP buffer 
		Write_Ethernet_Frame (buffer,*bufferlen);
		return(1);
	}
		
	if ((tcp_hdrflags1 & RST_FLAG) > 0) 
	{
		for (unsigned char a=0;a<Max_TCP_Sockets;a++)
			{
			tcp_socket= &tcpsockets[a]; //Pointer auf tcpsockets[a] holen
			if (tcp_socket->Store == tcp_srcport)
				{
				tcp_socket->Store = 0;
				break;
				}
			}
		return(1);
	}
		
	if ((tcp_hdrflags1 & FIN_FLAG) > 0) 
	{
		for (unsigned char a=0;a<Max_TCP_Sockets;a++)
			{
			tcp_socket= &tcpsockets[a]; //Pointer auf tcpsockets[a] holen

			if (tcp_socket->Store == tcp_srcport)
				{
				tcp_socket->Store = 0;
				break;
				}
			}
		//Setzen des Ack Flag
		buffer[TCP_HDRFLAGS+1] = RST_FLAG;
		//Speichert Sequenzcounter und Aknowledgecounter
		tcp_store(buffer);	
		//Seq_counter um 1 erh�en
		Seq_counter = Seq_counter + 1;
		//Erzeugt ein TCP buffer 
		tcp_make(buffer);			
		//Sendet das erzeugte TCP buffer 
		Write_Ethernet_Frame (buffer,*bufferlen);	
		return(1);
	}
return(0);
}

//############################################################################
//Verwaltet TCP Stack 
char TCP_Stack (char *buffer,int *bufferlen,unsigned char *Stackpointer)
//############################################################################
{
	//ist fr Verbindungsaufbau zust�dig TCP SYNC
	if (TCP_OPEN(buffer,bufferlen)==1)
		{
		return(1);//keine Daten fr Anwendung
		}
	
	unsigned int	TCP_Socket = (buffer[TCP_SRCPORT]<<8) + buffer[TCP_SRCPORT+1];

	for (unsigned char a=0;a<Max_TCP_Sockets;a++)
		{
		tcp_socket= &tcpsockets[a]; //Pointer auf tcpsockets[a] holen

		if(TCP_Socket == tcp_socket->Store)
			{
			if ((buffer[TCP_HDRFLAGS+1]&PSH_FLAG) > 0 
				&& (tcp_socket->Status == TCP_SOCKET_OPEN1 || tcp_socket->Status == TCP_SOCKET_OPEN2))
				{
				*Stackpointer = a;
				return(0); //Daten fr Anwendung
				}
			
			if (tcp_socket->Status == TCP_SOCKET_CLOSE)
				{
				tcp_socket->Store = TCP_SOCKET_NOT_USE;
				tcp_socket->Status = 0; //TCP Socket wird im TCP STACK geschlossen
			//	printf("TCP Socket Close Socket:%d Stack:%d\n",TCP_Socket,a);
				TCP_PORT_CLOSE (buffer,bufferlen);
				*Stackpointer = a;
				return(1); //Keine Daten fr Anwendung
				}
			
			if (tcp_socket->Status == TCP_SOCKET_NOT_USE)
				{
			//	printf("TCP Socket Open Socket:%d Stack:%d\n",TCP_Socket,a);
				tcp_socket->Status = TCP_SOCKET_OPEN1; //TCP Socket wird im TCP Stack ge�fnet
				*Stackpointer = a;
				return(0); //ACK fr Anwendung
				}
			
			if ((buffer[TCP_HDRFLAGS+1]&ACK_FLAG) > 0 
				&& (tcp_socket->Status == TCP_SOCKET_OPEN1 || tcp_socket->Status == TCP_SOCKET_OPEN2))
				{
				*Stackpointer = a;
				return(0); //ACK fr Anwendung
				}
			}
		}
	return (1);
}




