#include <avr/io.h>
#include "net.h"
#include "enc28j60.h"
#include <avr/pgmspace.h>
#include "avr_compat.h"
static uint8_t macaddr[6];
static uint8_t ipaddr[4];
static int16_t info_hdr_len=0;
static int16_t info_data_len=0;
static uint8_t seqnum=0xa;
extern void init_ip_arp(uint8_t *mymac,uint8_t *myip);
extern uint8_t eth_type_is_arp_and_my_ip(uint8_t *buf,uint16_t len);
extern uint8_t eth_type_is_ip_and_my_ip(uint8_t *buf,uint16_t len);
extern void make_arp_answer_from_request(uint8_t *buf);
extern void make_echo_reply_from_request(uint8_t *buf,uint16_t len);
extern void make_udp_reply_from_request(uint8_t *buf,char *data,uint8_t datalen,uint16_t port);
extern void make_tcp_synack_from_syn(uint8_t *buf);
extern void init_len_info(uint8_t *buf);
extern uint16_t get_tcp_data_pointer(void);
extern uint16_t fill_tcp_data_p(uint8_t *buf,uint16_t pos, const prog_char *progmem_s);
extern uint16_t fill_tcp_data(uint8_t *buf,uint16_t pos, const char *s);
extern void make_tcp_ack_from_any(uint8_t *buf);
extern void make_tcp_ack_with_data(uint8_t *buf,uint16_t dlen);


uint16_t checksum(uint8_t *buf, uint16_t len, uint8_t type) // вычисляем контрольную сумму для ip заголовка
{
       
        uint32_t sum = 0;
		if(type==1)
		  {
           sum+=IP_PROTO_UDP_V; 
           sum+=len-8; 
		  }
        if(type==2)
		  {
           sum+=IP_PROTO_TCP_V; 
           sum+=len-8; 
		  }
        while(len >1)
		  {
                sum += 0xFFFF & (*buf<<8|*(buf+1));
                buf+=2;
                len-=2;
        }
        
        if (len)
		{
                sum += (0xFF & *buf)<<8;
        }
        
        while (sum>>16)
		{
                sum = (sum & 0xFFFF)+(sum >> 16);
        }
       
        return( (uint16_t) sum ^ 0xFFFF);
}


void init_ip_arp(uint8_t *mymac,uint8_t *myip)// функция генерации ip- и MAC-адресов, которые будут переданы в пакет и фрейм соответственно
{
        uint8_t i=0;
        while(i<4)
		{
                ipaddr[i]=myip[i];// присваиваем ip-адресу, который впоследствии будет отправлен в ip- пакете значение нашего ip 
                i++;
        }
        i=0;
        while(i<6)
		{
                macaddr[i]=mymac[i];// присваиваем MAC-адресу, который впоследствии будет отправлен в Ethernet-фрейме  значение нашего MAC
                i++;
        }
}

uint8_t eth_type_is_arp_and_my_ip(uint8_t *buf,uint16_t len)// функция проверки, является ли полученный пакет ARP-запросом и предназначен ли нам?
{
        uint8_t i=0;
        //  
        if (len<41)
		{
                return(0);
        }
        if(buf[ETH_TYPE_H_P] != ETHTYPE_ARP_H_V || 
           buf[ETH_TYPE_L_P] != ETHTYPE_ARP_L_V)
		{
                return(0);
        }
        while(i<4)
		{
                if(buf[ETH_ARP_DST_IP_P+i] != ipaddr[i])
				{
                        return(0);
                }
                i++;
        }
        return(1);//в случае успеха возвращает значение 1
}

uint8_t eth_type_is_ip_and_my_ip(uint8_t *buf,uint16_t len)// функция проверки, адресован ли полученный IP пакет нам?
        {uint8_t i=0;
        
        if (len<42){
                return(0);
        }
        if(buf[ETH_TYPE_H_P]!=ETHTYPE_IP_H_V || 
           buf[ETH_TYPE_L_P]!=ETHTYPE_IP_L_V){
                return(0);
        }
        if (buf[IP_HEADER_LEN_VER_P]!=0x45){
               
                return(0);
        }
        while(i<4){
                if(buf[IP_DST_P+i]!=ipaddr[i]){
                        return(0);
                }
                i++;
        }
        return(1);//если да, то возвращает 1
}

void make_eth(uint8_t *buf)//функция замены MAC-адреса источника на МАС-адрес получателя
{
        uint8_t i=0;
        
        while(i<6){
                buf[ETH_DST_MAC +i]=buf[ETH_SRC_MAC +i];
                buf[ETH_SRC_MAC +i]=macaddr[i];
                i++;
        }
}
void fill_ip_hdr_checksum(uint8_t *buf)// функция генерации контрольной суммы, флагов, времени жизни для отправляемого IP пакета
{
        uint16_t ck;
        buf[IP_CHECKSUM_P]=0;
        buf[IP_CHECKSUM_P+1]=0;
        buf[IP_FLAGS_P]=0x40; 
        buf[IP_FLAGS_P+1]=0;  
        buf[IP_TTL_P]=64; 
        ck=checksum(&buf[IP_P], IP_HEADER_LEN,0);
        buf[IP_CHECKSUM_P]=ck>>8;
        buf[IP_CHECKSUM_P+1]=ck& 0xff;
}


void make_ip(uint8_t *buf)//функция генерации ip пакета для отправления
{
        uint8_t i=0;
        while(i<4)
		{
                buf[IP_DST_P+i]=buf[IP_SRC_P+i];
                buf[IP_SRC_P+i]=ipaddr[i];
                i++;
        }
        fill_ip_hdr_checksum(buf);
}


void make_arp_answer_from_request(uint8_t *buf)// функция генерации ARP-ответа для отправления
{
        uint8_t i=0;
        
        make_eth(buf);
        buf[ETH_ARP_OPCODE_H_P]=ETH_ARP_OPCODE_REPLY_H_V;
        buf[ETH_ARP_OPCODE_L_P]=ETH_ARP_OPCODE_REPLY_L_V;
       
        while(i<6){
                buf[ETH_ARP_DST_MAC_P+i]=buf[ETH_ARP_SRC_MAC_P+i];
                buf[ETH_ARP_SRC_MAC_P+i]=macaddr[i];
                i++;
        }
        i=0;
        while(i<4){
                buf[ETH_ARP_DST_IP_P+i]=buf[ETH_ARP_SRC_IP_P+i];
                buf[ETH_ARP_SRC_IP_P+i]=ipaddr[i];
                i++;
        }
        
        enc28j60PacketSend(42,buf); 
}

void make_echo_reply_from_request(uint8_t *buf,uint16_t len)// функция генерации понг-ответа для отправления
{
        make_eth(buf);
        make_ip(buf);
        buf[ICMP_TYPE_P]=ICMP_TYPE_ECHOREPLY_V;
        if (buf[ICMP_CHECKSUM_P] > (0xff-0x08)){
                buf[ICMP_CHECKSUM_P+1]++;
        }
        buf[ICMP_CHECKSUM_P]+=0x08;
        //
        enc28j60PacketSend(len,buf);
}
void make_tcphead(uint8_t *buf,uint16_t rel_ack_num,uint8_t mss,uint8_t cp_seq)//функция генерации заголовка TCP для последующей отправки
{
  uint8_t i=0;
  uint8_t tseq;
  while(i<2)
   {
    buf[TCP_DST_PORT_H_P+i]=buf[TCP_SRC_PORT_H_P+i];
    buf[TCP_SRC_PORT_H_P+i]=0; // clear source port
    i++;
   }
        
  buf[TCP_SRC_PORT_L_P]=80;
  i=4;
  while(i>0)
   {
    rel_ack_num=buf[TCP_SEQ_H_P+i-1]+rel_ack_num;
    tseq=buf[TCP_SEQACK_H_P+i-1];
    buf[TCP_SEQACK_H_P+i-1]=0xff&rel_ack_num;
    if (cp_seq)
	 {
      buf[TCP_SEQ_H_P+i-1]=tseq;
     }
	else
	 {
      buf[TCP_SEQ_H_P+i-1]= 0;
     }
    rel_ack_num=rel_ack_num>>8;
    i--;
     }
    if (cp_seq==0)
	 {
      buf[TCP_SEQ_H_P+0]= 0;
      buf[TCP_SEQ_H_P+1]= 0;
      buf[TCP_SEQ_H_P+2]= seqnum; 
      buf[TCP_SEQ_H_P+3]= 0;
      seqnum+=2;
     }
     buf[TCP_CHECKSUM_H_P]=0;
     buf[TCP_CHECKSUM_L_P]=0;
     if (mss)
	  {
       buf[TCP_OPTIONS_P]=2;
       buf[TCP_OPTIONS_P+1]=4;
       buf[TCP_OPTIONS_P+2]=0x05; 
       buf[TCP_OPTIONS_P+3]=0x80;
       buf[TCP_HEADER_LEN_P]=0x60;
      }
	 else
	  {
       buf[TCP_HEADER_LEN_P]=0x50;
      }
}

void make_tcp_synack_from_syn(uint8_t *buf)//функция отправки подтверждения открытия соединения
{
        uint16_t ck;
        make_eth(buf);
        buf[IP_TOTLEN_H_P]=0;
        buf[IP_TOTLEN_L_P]=IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+4;
        make_ip(buf);
        buf[TCP_FLAGS_P]=TCP_FLAGS_SYNACK_V;
        make_tcphead(buf,1,1,0);
        ck=checksum(&buf[IP_SRC_P], 8+TCP_HEADER_LEN_PLAIN+4,2);
        buf[TCP_CHECKSUM_H_P]=ck>>8;
        buf[TCP_CHECKSUM_L_P]=ck& 0xff;
        enc28j60PacketSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+4+ETH_HEADER_LEN,buf);
}
uint16_t get_tcp_data_pointer(void)//функция расчета  положения первого октета данных в буфере
{
        if (info_data_len)
		 {
          return((uint16_t)TCP_SRC_PORT_H_P+info_hdr_len);
         }
		else
		 {
          return(0);
         }
}
void init_len_info(uint8_t *buf)//функция определения размера TCP заголовка и принятых данных
{
        info_data_len=(buf[IP_TOTLEN_H_P]<<8)|(buf[IP_TOTLEN_L_P]&0xff);
        info_data_len-=IP_HEADER_LEN;
        info_hdr_len=(buf[TCP_HEADER_LEN_P]>>4)*4;
        info_data_len-=info_hdr_len;
        if (info_data_len<=0)
		 {
          info_data_len=0;
         }
}
uint16_t fill_tcp_data_p(uint8_t *buf,uint16_t pos, const prog_char *progmem_s)//функция записи строковых данных в буфер
{
        char c;
        while ((c = pgm_read_byte(progmem_s++))) 
		{
         buf[TCP_CHECKSUM_L_P+3+pos]=c;
         pos++;
        }
        return(pos);
}
uint16_t fill_tcp_data(uint8_t *buf,uint16_t pos, const char *s)//функция записи строковых данных в буфер
{
        while (*s) 
		{
         buf[TCP_CHECKSUM_L_P+3+pos]=*s;
         pos++;
         s++;
        }
        return(pos);
}
void make_tcp_ack_from_any(uint8_t *buf)// функция генерации подтверждения любого запроса
{
        uint16_t j;
        make_eth(buf);
        buf[TCP_FLAGS_P]=TCP_FLAGS_ACK_V;
        if (info_data_len==0)
		{
         make_tcphead(buf,1,0,1); 
        }
		else
		 {
          make_tcphead(buf,info_data_len,0,1); 
         }
        j=IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN;
        buf[IP_TOTLEN_H_P]=j>>8;
        buf[IP_TOTLEN_L_P]=j& 0xff;
        make_ip(buf);
        j=checksum(&buf[IP_SRC_P], 8+TCP_HEADER_LEN_PLAIN,2);
        buf[TCP_CHECKSUM_H_P]=j>>8;
        buf[TCP_CHECKSUM_L_P]=j& 0xff;
        enc28j60PacketSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+ETH_HEADER_LEN,buf);
}
void make_tcp_ack_with_data(uint8_t *buf,uint16_t dlen)
{
 uint16_t j;
 buf[TCP_FLAGS_P]=TCP_FLAGS_ACK_V|TCP_FLAGS_PUSH_V|TCP_FLAGS_FIN_V;
 j=IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+dlen;
 buf[IP_TOTLEN_H_P]=j>>8;
 buf[IP_TOTLEN_L_P]=j& 0xff;
 fill_ip_hdr_checksum(buf);
 buf[TCP_CHECKSUM_H_P]=0;
 buf[TCP_CHECKSUM_L_P]=0;
 j=checksum(&buf[IP_SRC_P], 8+TCP_HEADER_LEN_PLAIN+dlen,2);
 buf[TCP_CHECKSUM_H_P]=j>>8;
 buf[TCP_CHECKSUM_L_P]=j& 0xff;
 enc28j60PacketSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+dlen+ETH_HEADER_LEN,buf);
}






