/*
 * Copyright (c) 1988, 1990 The Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that: (1) source code distributions
 * retain the above copyright notice and this paragraph in its entirety, (2)
 * distributions including binary code include the above copyright notice and
 * this paragraph in its entirety in the documentation or other materials
 * provided with the distribution, and (3) all advertising materials mentioning
 * features or use of this software display the following acknowledgement:
 * ``This product includes software developed by the University of California,
 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
 * the University nor the names of its contributors may be used to endorse
 * or promote products derived from this software without specific prior
 * written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Author: Scott R. Presnell (srp@cgl.ucsf.edu)
 *
 */
#ifndef lint
static  char rcsid[] =
    "@(#)$Header: ethersnoop.c,v 1.2 93/10/11 15:58:59 mogul Exp $ (UCSF)";
#endif

#include <stdio.h>
#include <netdb.h>
#include <ctype.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/ioctl.h>

#include <net/raw.h>

#include "stat.h"
#include "packet.h"

#define ETHERHDRPAD	RAW_HDRPAD(sizeof(struct ether_header))

struct etherpacket {
	struct snoopheader	snoop;
	char			pad[ETHERHDRPAD];
	struct ether_header	ether;
	char			data[ETHERMTU];
};

#define DATANEEDED (64+sizeof(union ip_data)+sizeof(struct ether_header))
#define CHUNKSIZE (DATANEEDED * 32)
#define SOCKBUFSIZ (CHUNKSIZE * 16)

extern int errno;
int if_fd = -1;
extern char *EtherIface;

u_char *buf;
u_long chunksize;
int snaplen = DATANEEDED;

initdevice (EtherType)
	int EtherType;
{
	struct sockaddr_raw sr;
	struct snoopfilter sf;
	int cc = SOCKBUFSIZ;
	int on = 1;

	if (!buf) {
		chunksize = CHUNKSIZE;
		if ((buf = (u_char *)malloc(chunksize)) == NULL) {
			printf("MEMORY SHORTAGE: packet buf\n");
			exit(1);
		}
    	}

	/* do nothing if allready initialized */
	if (if_fd >= 0)
		return;

	if ((if_fd = socket(AF_RAW, SOCK_RAW, RAWPROTO_SNOOP)) < 0) {
		perror("socket");
		exit(-1);
	}

	sr.sr_family = AF_RAW;
	sr.sr_port = 0;
	strncpy(sr.sr_ifname, EtherIface, sizeof sr.sr_ifname);

	if (bind(if_fd, (struct sockaddr *) &sr, sizeof (sr)) < 0) {
		perror("bind");
		exit(1);
	}

	bzero((char *) &sf, sizeof sf);

	if (ioctl(if_fd, SIOCADDSNOOP, &sf) < 0) {
		perror("ioctl: adding snoop filter");
		exit(1);
	}

	if (ioctl(if_fd, SIOCSNOOPLEN, &snaplen) < 0) {
		perror("ioctl: SIOCSNOOPLEN");
		exit(1);
	}

	setsockopt(if_fd, SOL_SOCKET, SO_RCVBUF, (char *) &cc, sizeof cc);

	if (ioctl(if_fd, SIOCSNOOPING, &on) < 0) {
		perror("ioctl: turn on snoop");
		exit(1);
	}
}


deinitdevice()
{
	close(if_fd);
	if_fd = -1;
	free(buf);
	buf = 0;
}


readether()
{
	struct etherpacket *ep;
	int datalen;
	int len;
	u_char *bp;
	u_char *bufstop;

	if (if_fd < 0)
		return;

	if ((len = read(if_fd, buf, (int)chunksize)) < 0) {
		perror("Packet buffer read");
		exit(1);
	}

	if (! len)
		return;

	/* Process the buffer */

	bufstop = buf + len;

	for (bp = buf; bp < bufstop;
	     bp += (sizeof(struct snoopheader) + ETHERHDRPAD + datalen)) {

		ep = (struct etherpacket *)bp;
		datalen = ep->snoop.snoop_packetlen;

		if (ep->snoop.snoop_flags & SN_ERROR)
			continue;

		parse (&ep->ether, snaplen < datalen ? snaplen : datalen,
		       datalen, ep->snoop.snoop_timestamp);
	}
}

/*
** Return TRUE iff something interesting to report.
** Doesn't reference "outp" if it returns FALSE.
*/

boolean if_stats(outp)
     char *outp;
{
  /* XXX */
  return FALSE;
}
