#include "config.h"
#include "packet.h"
#include "header.h"

/*
 * initialize network interface controller
 */

init_evars()
{
	evars.monport = 0xFFFF;
	evars.connected = FALSE;
	evars.host_ipaddr = 0;
	evars.seq_num = 0;
	evars.save_num = 0;
	reset_host_eaddr();
}

initialize(etype)
{  
	register int	i;

	init_3com(etype);
	init_evars();
	evars.overwrite_error=0;
	evars.fail_transmit=0;
	for (i = 0; i < 6; i++)
		if (evars.eaddr[i] != 0xff && evars.eaddr[i] != 0)
			return(1);
	return(0);
}

/*
 * Process incoming ARP's
 */
arpin()
{
	struct arppak *ar;
	ar = (struct arppak *) evars.packet.ep_data;

	/* respond to ARPs with matching target internet address */
	if( (net2hs(ar->ar_op) == AR_REQ ) && (ar->ar_tpa == evars.ipaddr ) )
	{
	   ar->ar_op = hs2net(AR_RPLY);	/* operation to reply */
	   ar->ar_tpa = ar->ar_spa; 	/* target IP address */
	   ar->ar_spa = evars.ipaddr; 	/* sender IP address */
	   blkcopy(ar->ar_tha,
	    evars.packet.ep_hdr.e_src,3); 	/* set target physical address */
	   blkcopy(ar->ar_sha, &evars.eaddr[0], 3);
	   ar->ar_spa = evars.ipaddr;

	   blkcopy(evars.packet.ep_hdr.e_dest,
		   evars.packet.ep_hdr.e_src,3);
	   evars.packet.ep_hdr.rbc -= 4;

	   if(!ewrite())
		return(1);
	   evars.fail_transmit++;
	   return(0);

	} else
		return(0);
} /* arpin */

/*
 * Process IP packets
 * Respond to ICMP echo requests - this is mandatory for
 * all IP implementations.
 */

ipin()
{
    struct ip *ipp;

	ipp = (struct ip *)evars.packet.ep_data;
	if ((evars.packet.ep_hdr.rstatus & 0x20) == 0)  
	{
		switch(ipp->i_proto)
		{
		case IPRO_ICMP:
		    icmp_in();
		    return(0);

		case IPRO_UDP:
		    /* PUTSTR("UDP packet for me!!\n"); */
		    return(1);
		
		default:
		    return(0);
		}
	} else
		return(0);
} /* ipin */

#define ICRPECH 0		/* Echo Reply */
#define ICRQECH 8		/* Echo request */

struct icmp {
	char ic_typ;		/* ICMP message type */
	char ic_code;		/* Code */
	short ic_cksum;		/* Checksum of header */
	short ic_id;		/* for echo type, a message id */
	short ic_seq;		/* for echo type, a seq. num */
	char ic_data[1];	/* data area of ICMP */
};

/*
 * Process only the mandatory echo request.
 * Other ICMP requests are ignored.
 */

icmp_in()
{
    struct ip *ipptr;
    struct icmp *icmpptr;
    int len;
    char temp_addr[4];

	ipptr = (struct ip *)evars.packet.ep_data;
	icmpptr = (struct icmp *) ipptr->i_data;

	if(icmpptr->ic_typ == ICRQECH) 
	{
		/*
		 * check if packet had a physical match
		 */
 		if ((evars.packet.ep_hdr.rstatus & 0x20) == 0)  {
			len = net2hs(ipptr->i_paclen) - IPHLEN;
			if (len & 1)
				ipptr->i_data[len++] = 0;
			icmpptr->ic_typ = hs2net(ICRPECH);  /* DEBUG */
			icmpptr->ic_cksum = 0;
			icmpptr->ic_cksum = cksum(icmpptr,len/2);

			ipptr->i_dest = ipptr->i_src;
			ipptr->i_src = evars.ipaddr;
			ipptr->i_paclen = hs2net(IPHLEN + len);
			ipptr->i_cksum = 0;
			/*
			 * checksum only includes header -
			 * 10 words (20 bytes) long
			 */
			ipptr->i_cksum = cksum(ipptr,IPHLEN/2); 

			blkcopy(evars.packet.ep_hdr.e_dest,
				evars.packet.ep_hdr.e_src,3);
			evars.packet.ep_hdr.rbc -= 4; 
			if(!ewrite()) {
				return(1); 
			} else {
				evars.fail_transmit++;
				return(0);
			}
		} else
			return(0);
	} 
	return(0); /* not an echo request */
} /* icmp_in */
