#include "ether.h"

char etmyaddr[6];
char etbroad[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

et_init() {
	int i;

	select(AUX);

	put(0x81);
	put(0);

	select(ADDRPROM);
	put(0);

	printf("My address is ");
	for(i=0; i<6; i++)
		printf("%02x", (etmyaddr[i] = get()) & 0xff);

	printf("\n");

	for(i=0; i<6; i++) {
		select(i);
		put(etmyaddr[i]);
		}

	select(RCVCMD);
	put(0xe0);

	select(ADDRPROM);
	put(0);

	select(AUX);
	put(0x30);

	}

et_read(data, size)
	register char *data;
	int size; {
	int i;
	int high, low;
	unsigned len;
	int A=0;

	select(AUX);
	if((get() & 0x30) == 0x30) return 0;

	if(get() & 0x20) A = 1;

	select(ADDRPROM);
	put(0);

	if(A) select(RCVA);
	else select(RCVB);

	high = get();
	low = get();

	len = (((high & 0x07) << 8) + ( low&0xff) - 2) & 0x7ff;

	if(len > size)
		printf("too long, dropping\n");
	else for(i=0; i<len; i++)
		*data++ = get();

	select(RCVCMD);
	put(0xe0);

	select(ADDRPROM);
	put(0);

	select(AUX);
/*	printf("rd complete: aux %02x\n", get()&0xff);	*/
	put((get()&0x30) | (A ? 0x10 : 0x20));

	return size >= len ? len : 0;
	}

et_write(p, len)
	char *p;
	int len; {
	int i,j;
	int low, high;

/*	printf("et_send %d bytes at %08X\n", len, p);	*/
	etadcpy(etmyaddr, ((struct et_hdr *)p)->et_src);
	select(XMIT);
	put(0);
	select(COLCOUNT);
	put(0);

	if(len < 60) len = 60;

	high = ((2048-len)>>8)&0xff;
	low = (2048-len)&0xff;

/*	printf("high is %04x, low is %04x\n", high, low);	*/

	select(XMITMSB);
	put(high);
	select(XMITLSB);
	put(low);

	select(XMITBUF);
	for(i=0; i<len; i++) {
/*		printf("%02x ", *p&0xff);
		for(j=0; j<5000; j++);
		if((i+1)%20 == 0) printf("\n");	*/
		put(*p++);
		}

	select(XMITMSB);
	put(high);
	select(XMITLSB);
	put(low);

/*	printf("About to xmit\n");	*/
	select(AUX);

	put((get() & 0x30) | 0x08) ;

	while(get() & 0x08) ;

	}

#define	ARETH	0x1		/* ethernet hardware type */
#define	ARIP	0x800		/* internet protocol type */
#define	ARARP	0x806
#define	ARREQ	0x1		/* byte swapped request opcode */
#define	ARREP	0x2		/* byte swapped reply opcode */

struct adr {
	struct	et_hdr	ar_et;
	short	ar_hd;		/* hardware type */
	short	ar_pro;		/* protcol type */
	char		ar_hln;		/* hardware addr length */
	char		ar_pln;		/* protocol header length */
	short	ar_op;		/* opcode */
	char		ar_sha[6];	/* sender hardware address */
	long		ar_spa;		/* sender protocol address */
	char		ar_tha[6];	/* target hardware address */
	long		ar_tpa;		/* target protocol address */
	};

/* Send an address request packet for internet address ipaddr. This routine
	doesn't wait to receive a reply. */

static long cachip = 0;
static char cachet[6];
static char buffer[500];

etarp(ipaddr, eth)
	long ipaddr;
	char *eth; {
	struct adr adr;
	struct adr *padr2 = (struct adr *)buffer;
	int i;

	if(cachip == ipaddr) {
		etadcpy(cachet, eth);
		return;
		}

	etadcpy(etbroad, adr.ar_et.et_dst);
	etadcpy(etmyaddr, adr.ar_et.et_src);
	adr.ar_et.et_type = ARARP;
	adr.ar_hd = ARETH;
	adr.ar_pro = ARIP;
	adr.ar_hln = 6;
	adr.ar_pln = 4;
	adr.ar_op  = ARREQ;
	etadcpy(etmyaddr, adr.ar_sha);
	adr.ar_spa = in_me;
	adr.ar_tpa = ipaddr;

	et_write(&adr, sizeof(struct adr));

	while(1) {
	while(!et_read(buffer, 500)) ;

	if(padr2->ar_et.et_type == ARARP && padr2->ar_op == ARREP) {
		etadcpy(padr2->ar_sha, cachet);
		etadcpy(cachet, eth);
		cachip = ipaddr;
		return;
		}
	
	}

	}

dump(p)
	char *p; {
	int i,j;

	for(i=1; i< 200; i++) {
		printf("%02x ", *p++&0xff);
		for(j=0; j<500; j++) ;
		if(i%16 == 0) printf("\n");
	}

	printf("\n");
	}
