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

/*
 * Ethernet IO routines 
 */

/*
 * Initialization
 */

#define	M_ECHO	0x4
#define	M_CRNL	0x8

Einit(etype)
{
	return(initialize(etype));
}

/*
 * Read routine:
 * if nbytes > 0, monitor wants exactly `nbytes',
 * if nbytes < 0, monitor wants up to nl/cr, but no more than `nbytes'.
 */

#define BSIZ	256

int Eread(buf, nbytes)
char	*buf;
int	nbytes;
{
	register char *p, *q;
	unsigned short nlflag;
	unsigned int	lost;
	int	len, j;

again:
	nlflag = nbytes < 0;
	if (nlflag)
		nbytes = -nbytes;
	do {
		getpacket();
		p = (char *)receive_udp(&len);
	} while (len == 0);
	if (Estrncmp(p, "bl ",2) || Estrncmp(p, "BL ",2)) {
		do_load_cmd(p);
		goto again;
	}
	if (Estrncmp(p, "el ",2) || Estrncmp(p, "EL ",2)) {
		send_messB("*");
		goto again;
	}
	/*
	 * lost packet message
	 */
	if (Estrncmp(p, "lt ",2) || Estrncmp(p, "LT ",2)) {
		jscan(p+3, &lost, 4);
		recover_packet((short) (lost & 0xffff));
		send_messB("*");
		goto again;
	}
	for (j = nbytes, q = buf; (j > 0) && (len > 0); j--, len--)
	{
		*q = *p;
		if (nlflag) {
			if (*p == '\r') {
				break;
			}
			if (*q == '\0' || *q == '\n') {
				*q = '\r';
				break;
			}
		}
		p++;
		q++;
	}
	if (len == 0)
		*q = '\r';
	return(q - buf + 1);
}

/*
 * Write routine
 */

Ewrite(bufstart, bufend)
char *bufstart, *bufend;
{
	char	*p;
	char	lbuf[100], *q;
	int	nb;

	prepare_udp();
	nb = bufend - bufstart;
	if (nb > sizeof(lbuf)) {
		nb = sizeof(lbuf) - 1;
	}
	bcopy(bufstart, lbuf, nb);
	lbuf[nb] = '\0';
	q = lbuf;
	PUTSTR("Outbuf: ");
	dumpacket(q);
	while ((*q == '\r') && (nb > 0)) {
		q++;
		nb--;
	}
	if (nb > 0) {
		send_messB(q);
	}
	return(nb);
}


/*
 * Eload - load routine
 *
 * Loading is done via the BL command:
 * Each packet has an address, length and up to 1k bytes of load
 * data.
 */

struct loadbuf {
	unsigned long loadaddr;
	unsigned short len;
	short clen;
	char	data;
};

int Eload(src)
char *src;
{
	register int	*dp, *dq;
	register char *p, *q;
	struct loadbuf *lp;
	int	i;
	int	nb;
	char	evrfaddr[20];

	lp = (struct loadbuf *)src;
	dq = (int *)lp->loadaddr;
	dp = (int *)&lp->data;
	i = (int)lp->len;
	nb = i;
	if (nb >= sizeof(int)) {
		*dq = *dp;
		nb -= sizeof(int);
		if (writevrfy(dq, dp) == 0)
			return(0);
		dq++;
		dp++;
		for (i = nb; i >= sizeof(int); i -= sizeof(int)) {
			*dq++ = *dp++;
		}
		if (writevrfy(dq-1, dp-1) == 0)
			return(0);
	}
	/*
	 * take care of leftovers (0 to 3 bytes)
	 */
	q = (char *)dq;
	p = (char *)dp;
	for (; i > 0; i--) {
		*q = *p;
		if (*q != *p) {
			evrfaddr[0] = '\0';
			addstr(evrfaddr, "E VRF ");
			addhex(evrfaddr+6, q, 8);
			evrfaddr[14] = '\0';
			mon_error(evrfaddr);
			return(0);
		}
		p++;
		q++;
	}
	return(1);
}

writevrfy(p1, p2)
int	*p1, *p2;
{
	char	evrfaddr[20] ;

	if (*p1 != *p2) {
		evrfaddr[0] = '\0';
		addstr(evrfaddr, "E VRF ");
		addhex(evrfaddr+6, p1, 8);
		evrfaddr[14] = '\0';
		mon_error(evrfaddr);
		return(0);
	}
	return(1);
}

/*
 * Get a packet from the net.
 *
 * Let in only IP packets, that are destined to us.
 * If no real packet is received for last RETRYCNT retries
 * the last message is resent and we enter the read loop
 * again.
 * Each packet is resent no more than RESENDCNT times
 */

getpacket()
{
	short	ptype;
	int	retries, resends;

	resends = 0;
again:
	retries = 0;
	while (1)
	{
		if(overwrite())
			evars.overwrite_error++;
		while(eread()) {
			if (++retries >= RETRYCNT) {
				if (++resends <= RESENDCNT)
					resend();
				goto again;
			}
		}
		switch (ptype = net2hs(evars.packet.ep_hdr.e_ptype)) {
		/*
		 * check for UDP packets
		 */
		case EP_IP:
			if (ipin()) {
				return;
			}
			break;

		/*
		 * check for ARP requests
		 */
		case EP_ARP:
			arpin();
			break;

		default:
			break; 
	
		} /* end switch */
	} /* while (1) */
}

/*
 */

do_load_cmd(cmd)
char	*cmd;
{
	int	addr, len;
	int	count,loading;
	char *p;
	
	/*
	 * skip over "bl "
	 */
	jscan(cmd+3, &addr, 8);
	prepare_udp();
	send_messB("*");

	loading = 1;
	do {
		getpacket();
		p = (char *)receive_udp(&len);
		/* If p == NULL try and get new packet 		   **
		** This may happens if we get two packets with the **
		** same sequence number				   */
		if (p != 0) {
		    if (len > 0) {
			loading = 0;
			if (!Estrncmp(p, "el ", 2)) {
				mon_error("?");
				break;
			}
		    } else {
		        if (Eload(p) == 0)
			    break;
		    }
		    prepare_udp();
		    send_messB("*");
		}
	} while (loading);
}

dumpacket(p)
register char *p;
{
#ifdef DEBUG
	register int	i;

	for (i = 0; i < 20; i++, p++) {
		if (*p < ' ') {
			PUTCHAR('^');
			PUTCHAR(*p + '@');
		} else if (*p == 0x7f) {
			PUTSTR("^?");
		} else {
			PUTCHAR(*p);
		}
		PUTCHAR(' ');
	}
	PUTSTR("\r\n");
#endif /* DEBUG */
}
