/*
 * $Id: pfilt.c,v 1.2 2005/02/01 18:06:29 c4chris Exp $
 */

#include "os.h"

#ifdef USE_PFILT
/*
 * pfilt.c - routines for messing with the packet filter
 *
 * Jeffrey Mogul
 * DECWRL
 * 
 */
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/file.h>
#include <net/if.h>
#include <signal.h>
#include <stdio.h>

#include <net/pfilt.h>

#include "nfswatch.h"
#include "externs.h"

static struct ifreq ifr;			/* holds interface name	*/

/*
 * setup_pfilt_dev - set up the packet filter
 */
int
setup_pfilt_dev(device)
char **device;
{
	int fd;
	struct timeval timeout;
	short enmode;
	short backlog = -1;	/* request the most */
	struct enfilter Filter;

	/*
	 * Open the packetfilter.  If it fails, we're out of
	 * devices.
	 */
	if ((fd = pfopen(*device, 0)) < 0) {
		return(-1);
	}

	/*
	 * We want the ethernet in promiscuous mode
	 */
	enmode = ENBATCH|ENTSTAMP|ENNONEXCL|ENPROMISC;
	if (ioctl(fd, EIOCMBIS, &enmode) < 0) {
		error("ioctl: EIOCMBIS");
		finish(-1);
	}

#ifdef ENCOPYALL
	/*
	 * Attempt to set "copyall" mode (see our own packets).
	 * Okay if this fails.
	 */
	enmode = ENCOPYALL;
	(void) ioctl(fd, EIOCMBIS, &enmode);
#endif

	/*
	 * Set the read timeout.
	 */
	timeout.tv_sec = 1;
	timeout.tv_usec = 0;
	if (ioctl(fd, EIOCSRTIMEOUT, &timeout) < 0) {
		error("ioctl: EIOCSRTIMEOUT");
		finish(-1);
	}

	/* set the backlog */
	if (ioctl(fd, EIOCSETW, &backlog) < 0) {
		error("ioctl: EIOCSETW");
		finish(-1);
	}

	/* set the truncation */
	if (ioctl(fd, EIOCTRUNCATE, &truncation) < 0) {
		error("ioctl: EIOCTRUNCATE");
		finish(-1);
	}

	/* find out the actual device name */
	if (*device == NULL) {
		if (ioctl(fd, EIOCIFNAME, &ifr) >= 0) {
			*device = ifr.ifr_name;
		}
		else {
			*device = "pf0";
		}
	}

	/* accept all packets */
	Filter.enf_Priority = 37;	/* anything > 2 */
	Filter.enf_FilterLen = 0;	/* means "always true" */
	if (ioctl(fd, EIOCSETF, &Filter) < 0) {
		error("ioctl: EIOCSETF");
		finish(-1);
	}

	return(fd);
}

/*
 * pfilt_devtype - return device type code for packet filter device
 */
int
pfilt_devtype(fd)
int fd;
{
	struct endevp devparams;

	if (ioctl(fd, EIOCDEVP, &devparams) < 0) {
		error("ioctl: EIOCDEVP");
		finish(-1);
	}

	switch (devparams.end_dev_type) {
	case ENDT_10MB:
		return(DLT_EN10MB);
		
#ifdef	ENDT_FDDI		/* HACK: to compile prior to Ultrix 4.2 */
	case ENDT_FDDI:
		return(DLT_FDDI);
#endif
		
	default:
		/*
		 * Currently, the Ultrix packet filter supports only
		 * Ethernet and FDDI.
		 */
		fprintf(stderr, "Packet filter data-link type %d unknown\n",
				devparams.end_dev_type);
		fprintf(stderr, "Assuming Ethernet\n");
		return(DLT_EN10MB);
	}
}

/*
 * flush_pfilt - flush data from the packet filter
 */
void
flush_pfilt(fd)
int fd;
{
	if (ioctl(fd, EIOCFLUSH) < 0) {
		error("ioctl: EIOCFLUSH");
		finish(-1);
	}
}
#endif /* USE_PFILT */
