#include <common.h>
#include <ip.h>
#include <strings.h>
#include <slip.h>
#include <icmp.h>

extern BYTE rxbuffer[];
extern BYTE txbuffer[];
extern WORD rxpos;
extern WORD txpos;
extern WORD datalen;

ipstats ipstat;

/*************************************************************************
 * void icmp_receive()
 * this function is called by the IP layer on reception of an ICMP
 * packet, only an echo request is responded to
 ************************************************************************/
void icmp_receive()
{
	WORD checks;
	/* increment ICMP stats counter */
	ipstat.icmprx++;
	/* if it's an ICMP type 8, echo request */
	if (rx_byte() == 8)
	{
		/* we need to begin copying ICMP data straight after the checksum
		 * word - ID and sequence are sent back unchanged, along with the 
		 * payload itself */
		discard_byte();		/* code */
		discard_byte();		/* checksum */
		discard_byte();		/* checksum */
		/* add the IP header to the transmit buffer */
		ip_header(PROTICMP);		
				
		tx_byte(0x00);	/* type 0 - Echo Reply */
		tx_byte(0x00);	/* code */
		/* the checksum field must be set to zero before calculating the
		 * checksum value */
		tx_byte(0x00);	/* checksum */
		tx_byte(0x00);	/* checksum */
		/* copy the ICMP data over to the transmit buffer */
		while (rxpos <= (IPSIZE+datalen))
		{
			copy_rx_byte(&txbuffer[txpos++]);
		}
		
		/* ICMP checksum - checksum of header and data
		 * start directly after IP header for, until end of IP packet
		 * stick the result starting 2 bytes into ICMP */
		checks = chksm(&txbuffer[IPSIZE],datalen);
		put_checksum(checks,&txbuffer[IPSIZE+2]);
		/* call SLIP to send the reply out */
		slip_send(&txbuffer,(IPSIZE+datalen));
		ipstat.icmptx++;
	} else {
		ipstat.icmpdrop++;
	}
}

void discard_byte()
{
	rxpos++;
}

/************************************************************************
 * WORD chksum(WORD *startpos, WORD checklen)
 * returns a standard internet checksum calculation of "checklen"
 * bytes from the transmit buffer, starting at "startpos"
 ***********************************************************************/
WORD chksm(WORD *startpos, WORD checklen)
{
	ulong sum = 0;
	WORD answer = 0;

	while (checklen > 1)
	{
		sum += *startpos++;
		checklen -= 2;
	}

	if (checklen == 1)
	{
		*(BYTE *)(&answer) = *(BYTE *)startpos;
		sum += answer;
	}

	sum = (sum >> 16) + (sum & 0xffff);
	sum += (sum >> 16);
	answer = ~sum;
	
	return answer;
}

void put_checksum(WORD check, WORD *put)
{
	*put = check;
}


syntax highlighted by Code2HTML, v. 0.9