#include <dos.h>
#include <stdio.h>
#include <string.h>
#include "pcdefs.h"
#include "shared.h"
#include "data.h"
#include "config.h"
#include "funcdef.h"

extern u_char *bios;

#ifdef notdef
void
arpinit()
{
	memcpy(arp.d.me, myether, DADDLEN);
	memcpy(arp.d.dest, etherall, DADDLEN);
	arp.d.type = EARP;		/* 0x0806 is ARP type */
	arp.hrd = htons(HTYPE);	/*  Ether = 1, swabbed  */
	arp.pro = htons(ARPPRO);  /* IP protocol = 0x0800, swabbed */
	arp.op = htons(ARPREQ);
	arp.hln = DADDLEN;		/* Ethernet hardware length */
	arp.pln = 4;			/* IP length = 4 */
	arp.spa = Scon.myip;		/* sender's IP addr */
	memcpy(arp.sha, myether, DADDLEN); /* sender's hardware addr */
	memcpy(arp.tha, etherall, DADDLEN); /* target hardware addr */
}
#endif

/***************************************************************************
*  netdlayer
*       get data layer address for insertion into outgoing packets.
*   searches based on ip number.  If it finds the address, ok, else . . .
*
*   Checks to see if the address is on the same network.  If it is,
*   then ARPs the machine to get address.  Forces pause between sending
*   arps to guarantee not saturating network.
*
*   If not on the same network, it needs the ether address of a 
*   gateway.  Searches the list of machines for a gateway flag.
*   Returns the first gateway found with an Ethernet address. 
*
*   Returns NULL if not here, or pointer to ether address if here.
*   If we don't have it, this also sends an ARP request so that the
*   next time we are called, the ARP reply may be here by then.
*
*/
u_char *
netdlayer(tipnum)
u_long	tipnum;
{
	u_char *cp;
	u_long	time, now;

	if (!pkshared->xmitarp.spa)
		return 0;

	tipnum = find_route(tipnum);
#ifdef notdef
	time = n_clicks() + ARPWAIT;	/* one second time out */
	do {
		cp = cachelook(tipnum);
		if (cp)
			break;
	} while (n_clicks() < time);
#else
	CLI;
	now = *(u_long *)&bios[0x46c];
	STI;
	time = now + ARPWAIT;		/* one second timeout */
	while (now < time) {
		if ((cp = cachelook(tipnum)) != 0)
			return cp;
		CLI;
		now = *(u_long *)&bios[0x46c];
		STI;
	}
#endif
	return 0;
}

/*************************************************************************
*  cachelook
*   look up information in the cache
*   returns the ethernet address from the cache for the IP number given.
*   Returns 0 on no valid entry, also if the entry present is too old.
*/
u_char *
cachelook(ipn)
u_long	ipn;
{
	int	i;
	static u_char addr[DADDLEN];
	static u_long	arptime;
	u_long time;
	u_char *sp;

/*
	time = n_clicks();
*/
	CLI;
	time = *(u_long *)&bios[0x46c];
	STI;
	for (i = 0; i < NARPC; i++) {
		if (ipn == pkshared->arpc[i].ip) {
			sp = pkshared->arpc[i].hrd;
			_fmemcpy(addr, sp, DADDLEN);
			if (pkshared->arpc[i].tm + CACHETO < time) {
				CLI;
				pkshared->arpc[i].ip = 0;
				pkshared->arpc[i].tm = 0;
				STI;
			}
			if (pkshared->arpc[i].tm + ARPRESEND < time &&
			    time > arptime) {
				pkshared->arpqueued = 2;
				pkshared->xmitarp.tpa = ipn;
				pkshared->xmitarp.op = htons(ARPREQ);
				_fmemcpy(pkshared->xmitarp.tha, etherall,
					DADDLEN);
				_fmemcpy(pkshared->xmitarp.d.dest, etherall,
					DADDLEN);
				(void) send_pkt(60);
				pkshared->arpqueued = 0;
			}
			return addr;
		}
	}
	if (time > arptime) {
		pkshared->arpqueued = 2;
		pkshared->xmitarp.tpa = ipn;
		pkshared->xmitarp.op = htons(ARPREQ);
		_fmemcpy(pkshared->xmitarp.tha, etherall, DADDLEN);
		_fmemcpy(pkshared->xmitarp.d.dest, etherall, DADDLEN);
		(void) send_pkt(60);
		pkshared->arpqueued = 0;
		arptime = time + ARPTO;
	}
	return 0;
}
