#include <common.h>
#include <slip.h>
#include <ip.h>
#include <icmp.h>
#include <udp.h>
#include <tcp.h>

ipheader ip;
ipstats ipstat;
WORD rxpos=0;
WORD txpos=0;
WORD datalen;
extern BYTE rxbuff[];
extern BYTE txbuffer[];
WORD ipid=1;

/* ************************************************************************
 * void ip_receive()
 * process the IP header, storing any required values in global
 * memory before passing control over to the next layer
 ************************************************************************/
void ip_receive()
{
	WORD ch;
	BYTE tempb;
	BYTE flags;
	BYTE proto;
	WORD offset;
	BYTE version;
	BYTE headerlen;
	BYTE n;
	/* increment receive statistics counter */
	ipstat.rxpackets++;
	/* place circular buffer pointer at start of buffer */
	rxpos=0;
	
	/* copy byte from receive buffer */
	copy_rx_byte(&tempb);
	/* retrieve version number */
	version = tempb >> 4;
	/* and discard the datagram if it's not v4 */
	if (version != 4)
	{
		ipstat.dropped++;
		return;
	}

	/* mask off upper four bits and store
	 * the ip header length for later use */
	headerlen = tempb & 15;
	/* discard the TOS */
	discard_byte();
	/* store the total length of the IP datagram
	 * to be read later by other protocols */
	copy_rx_word(&ip.totallen);
	/* discard the IPID */
	discard_word();
	
	/* read the 3 bit flags and 15 bit offset */
	copy_rx_byte(&tempb);
	flags = (tempb>>5);
	tempb &= 0x1F;
	copy_rx_byte(&offset);
	offset = ((WORD)tempb<<8)|offset;
	
	/* discard the datagram if it is fragmented
	 * (sometimes have unexpected problems with this) */
	if (offset || (flags & 0x01)) {
		ipstat.dropped++;
		return;
	}
	
	/* discard TTL field */
	discard_byte();
	/* store protocol field for demultiplexing later */
	copy_rx_byte(&proto);
	/* and just skip past the checksum */
	discard_word();
	/* copy the source address, to be used
	 * as the destination address of the next outgoing packet */
	copy_rx_byte(&ip.destaddr[0]);
	copy_rx_byte(&ip.destaddr[1]);
	copy_rx_byte(&ip.destaddr[2]);
	copy_rx_byte(&ip.destaddr[3]);
	
	/* ensure the destination address of incoming datagram
	 * matches the preconfigured address of the device
	 * otherwise, drop the datagram */
	if (rx_byte() != IP1 || rx_byte() != IP2 ||
		rx_byte() != IP3 || rx_byte() != IP4)
	{
		ipstat.dropped++;
		return;
	}
	
	/* options will come next, but we just want to discard them */
	for (n=5;n<headerlen;n++)
	{
		SkipLong();
	}
		
	/* length of data (everything after the header)
	 * totallen in 8 bits - headerlen in 32 bits, so multiply by 4 */
	datalen = ip.totallen - (headerlen<<2);

	/* calculate the checksum of the IP header */
	ch = chksm(&rxbuff[0],20);
	/* and silently drop tha packet if the checksum found to be incorrect */
	/* (sometimes problems here too..) */
	if (~ch != 0xFFFF)
	{
		ipstat.dropped++;
		return;
	}
	
	/* check the protocol field and pass to
	 * the appropriate higher layer, or discard */
	switch (proto)
	{
		case PROTICMP:
			icmp_receive();
			break;
		case PROTUDP;
			udp_receive();
			break;
		case PROTTCP:
			tcp_receive();
			break;
		default:
			break;
	}
}

/************************************************************************
 * void ip_header()
 * place an IP header in the transmit buffer, this is called by
 * the transport layer protocols (or ICMP)
 ***********************************************************************/
void ip_header(BYTE proto)
{
	WORD chk;
	
	/* type = 4, headerlen = 5 */
	tx_byte(0x45);
	/* Type of Service */
	tx_byte(0x00);	
	tx_word(ip.totallen);
	
	tx_word(ipid++);
	
	tx_byte(0x00);		/* flags and */
	tx_byte(0x00);		/* offset */
	tx_byte(0x40);		/* TTL - 64 */
	tx_byte(proto);		/* protocol */
	tx_byte(0x00);		/* checksum, 0 for now */
	tx_byte(0x00);		/* checksum too */
	tx_byte(IP1); 		/* source IP address */
	tx_byte(IP2);		/* the value of which is set */
	tx_byte(IP3);		/* in common.h */
	tx_byte(IP4); 		
	tx_byte(ip.destaddr[0]); /* destination IP address */
	tx_byte(ip.destaddr[1]); /* copied from the source */
	tx_byte(ip.destaddr[2]); /* address of the last packet */
	tx_byte(ip.destaddr[3]);  
	
	/* insert the IP checksum into the correct position in the header
	 * (an IP checksum is only calculated on the header itself)
	 * IPSIZE is the length of the header, in bytes
	 * IPCHKPOS is the number of bytes into the header the checksum appears */
	chk = chksm(&txbuffer[0],IPSIZE);
	put_checksum(chk,&txbuffer[IPCHKPOS]);
}




syntax highlighted by Code2HTML, v. 0.9