/*
 *	This file implementes /dev/arp, from which the arp table can be
 *	read.
 *
 *	12/15/94, Kay Roemer.
 */
#include <string.h>
#include "config.h"
#include "kerbind.h"
#include "file.h"
#include "atarierr.h"
#include "socket.h"
#include "net.h"
#include "timer.h"
#include "dummydev.h"
#include "inet.h"
#include "in.h"
#include "if.h"
#include "ifeth.h"
#include "arp.h"
#include "util.h"

/*
 * structure that can be read from /dev/arp
 */
struct arp_info {
	struct sockaddr_hw	praddr;
	struct sockaddr_hw	hwaddr;
	unsigned short		flags;
	unsigned short		links;
	unsigned long		tmout;
};

/*
 * arp hash table
 */
extern struct arp_entry *arptab[ARP_HASHSIZE];

/*
 * /dev/arp device driver
 */
static long arpdev_read (FILEPTR *, char *, long);

static DEVDRV arpdev = {
	dummydev_open, dummydev_write, arpdev_read,
	dummydev_lseek, dummydev_ioctl, dummydev_datime,
	dummydev_close, dummydev_select, dummydev_unselect
};

static struct dev_descr arpdev_descr = {
	&arpdev, 0, 0, 0
};

static char arpdev_name[] = "u:\\dev\\arp";


long
arpdev_init (void)
{
	return dummydev_init (arpdev_name, &arpdev_descr);
}

static long
arpdev_read (fp, buf, nbytes)
	FILEPTR *fp;
	char *buf;
	long nbytes;
{
	struct arp_info info, *infop = (struct arp_info *)buf;
	struct arp_entry *are = 0;
	long space, t;
	int i, j;

	for (space = nbytes; space >= sizeof (info); ++fp->pos) {
		i = fp->pos;
		for (j = 0; j < ARP_HASHSIZE && i >= 0; ++j) {
			are = arptab[j];
			for (; are && --i >= 0; are = are->prnext);
		}
		if (j >= ARP_HASHSIZE) break;
		memset (&info, 0, sizeof(info));
		/*
		 * Protocoll address
		 */
		info.praddr.shw_family = AF_LINK;
		info.praddr.shw_len = are->praddr.len;
		info.praddr.shw_type = are->prtype;
		if (are->flags & ATF_PRCOM) {
			memcpy (info.praddr.shw_addr, are->praddr.addr,
				are->praddr.len);
		}
		/*
		 * Hardware address
		 */
		info.hwaddr.shw_family = AF_LINK;
		info.hwaddr.shw_len = are->hwaddr.len;
		info.hwaddr.shw_type = are->hwtype;
		if (are->flags & ATF_HWCOM) {
			memcpy (info.hwaddr.shw_addr, are->hwaddr.addr,
				are->hwaddr.len);
		}
		info.flags = are->flags;
		info.links = are->links;
		t = event_delta (&are->tmout);
		info.tmout = (t < 0) ? 0 : t * EVTGRAN;

		*infop++ = info;
		space -= sizeof (info);
	}
	return (nbytes - space);
}
