[comp.sources.unix] v20i059: User-level interface to Ethernet, Part02/03

rsalz@uunet.uu.net (Rich Salz) (10/26/89)

Submitted-by: Alexander Dupuy <dupuy@cs.columbia.edu>
Posting-number: Volume 20, Issue 59
Archive-name: etherlib/part02

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 2 (of 3)."
# Contents:  ./GNUmake.mk ./Instructions ./SunBugs
#   ./src/Makefile ./src/dliopen.c ./src/enetopen.c ./src/ether.h
#   ./src/etherarp.c ./src/ethere2h.c ./src/ethere2ip.c
#   ./src/etherh2e.c ./src/etherhe2e.c ./src/etherints.c
#   ./src/etherip2e.c ./tests/ctp.h
# Wrapped by rsalz@papaya.bbn.com on Wed Oct 25 16:37:31 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f './GNUmake.mk' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./GNUmake.mk'\"
else
echo shar: Extracting \"'./GNUmake.mk'\" \(3104 characters\)
sed "s/^X//" >'./GNUmake.mk' <<'END_OF_FILE'
X#
X# Indirect GNU makefile for ethernet interface library
X#
X
X# Get pattern rules for %.ps
X
Xinclude ../GNUmake.config
X
X# This builds machine-dependent components for the ethernet interface library
X
X# VPATH directives
X
Xvpath %.h ../src
Xvpath %.c ../src:../tests
Xvpath %.3n ..
X
X
X# Configuration
X
XNIT := $(shell ls /usr/include/net/nit.h 2>/dev/null)
XNIT4 := $(shell ls /dev/nit 2>/dev/null)
XENET := $(shell ls /dev/enet/ 2>/dev/null)
X
X# Software components
X
XHDRS = ether.h libether.h
X
XSRCS = etheraddr.c etherints.c ethere2a.c ethera2e.c etherarp.c etherlocal.c \
X ethere2ip.c etherip2e.c ethere2h.c etherh2e.c etherhe2e.c
X
XALLSRCS := $(SRCS) \
X etherblock.c etherread.c etherreadv.c nitaddr.c \
X nit4self.c nit4intaddr.c nit4open.c nit4write.c nit4writev.c \
X nit3self.c nit3intaddr.c nit3open.c \
X nit3read.c nit3readv.c nit3write.c nit3writev.c \
X dliaddr.c dliself.c dliintaddr.c dliopen.c \
X dliread.c dlireadv.c dliwrite.c dliwritev.c \
X enetblock.c enetaddr.c enetself.c enetintaddr.c enetopen.c \
X enetwrite.c enetwritev.c
X
Xifneq ($(NIT4),)
XSRCS := $(SRCS) etherblock.c etherread.c etherreadv.c \
X nitaddr.c nit4self.c nit4intaddr.c nit4open.c nit4write.c nit4writev.c
XDEFINES := $(DEFINES) -DETHERDB
Xelse
Xifneq ($(NIT),)
XSRCS := $(SRCS) etherblock.c nitaddr.c nit3self.c nit3intaddr.c \
X nit3open.c nit3read.c nit3readv.c nit3write.c nit3writev.c
XDEFINES := $(DEFINES) -DETHERDB
Xendif
Xendif
X
Xifneq ($(findstring ultrix,$(SYSTEM)),)
XSRCS := $(SRCS) etherblock.c dliaddr.c dliself.c dliintaddr.c \
X dliopen.c dliread.c dlireadv.c dliwrite.c dliwritev.c
XDEFINES := $(DEFINES) -DETHERDB
Xelse
Xifneq ($(ENET),)
XSRCS := $(SRCS) etherread.c etherreadv.c enetblock.c enetaddr.c \
X enetintaddr.c enetself.c enetopen.c enetwrite.c enetwritev.c
X#INCLUDES = -I../enet/4.3
Xendif
Xendif
X
X# Compilation flags used
X
Xifeq ($(findstring gcc,$(CC)),)
X
XCFLAGS = $(OPT) $(DEFINES) $(INCLUDES)
X
Xelse
X
XCFLAGS = $(OPTG) $(DEFINES) $(INCLUDES)
X
Xendif
X
XINCLUDES := -I../src $(INCLUDES)
X
XOBJS = $(SRCS:.c=.o)
X
XLINTFLAGS = -bhuxz
X
X# Default dependency - remake all out of date object files
X
X.PHONY: default all
X
Xdefault: all
X
Xall: libether.a
X
Xlibether.a: $(OBJS)
Xifeq ($(findstring t,$(MAKEFLAGS)),)
X	ar curv $@ $(OBJS)
X	ranlib $@
Xelse
X	@echo $(MAKE) > /dev/null
X	touch $@
X	ranlib -t $@
Xendif
X
Xetheraddr.o: etheraddr.c
X	$(CC) $(CFLAGS) -R -c $< $(OUTPUT_OPTION)
X
Xtest: ethertest
X	./ethertest
X
Xethertest: ethertest.o libether.a
X
Xctp: ctp.o $(LIBDIR)/libether.a
X
X$(OBJS): $(HDRS)
X
X
X# Installation
X
Xinstall: $(LIBDIR)/libether.a $(INCDIR)/ether.h $(MANDIR)/man3/ether.3n
X
X# Fluff test
X
X.PHONY: lint
X
Xlint: $(SRCS) ethertest.c
X	-$(LINT) $(LINTFLAGS) $(DEFINES) $(INCLUDES) -I. $?
X
X
X# Vgrind formatted listing
X
XLISTS = $(ALLSRCS:.c=.ps) $(HDRS:.h=.ps) index.ps
X
X.PHONY: listing
X
Xlisting: index $(LISTS)
X
Xindex.ps: index
X	sort -fu -o index index
X	$(VGRIND) -t -x index > index.ps
X
Xindex: /dev/null
X	ctags -tv $(SRCS) $(HDRS) >> index 2>/dev/null
X
X
X# Utility operations
X
X.PHONY: clean cleanlists realclean
X
Xclean:
X	rm -f $(OBJS) libether.a ethertest.o ethertest ctp.o ctp
X
Xcleanlists:
X	rm -f $(LISTS) index
X
Xrealclean: clean cleanlists
END_OF_FILE
if test 3104 -ne `wc -c <'./GNUmake.mk'`; then
    echo shar: \"'./GNUmake.mk'\" unpacked with wrong size!
fi
# end of './GNUmake.mk'
fi
if test -f './Instructions' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./Instructions'\"
else
echo shar: Extracting \"'./Instructions'\" \(2921 characters\)
sed "s/^X//" >'./Instructions' <<'END_OF_FILE'
X
XThis ethernet access library is a part of the Columbia Netmate project which is
Xbeing released as a useful component in its own right.
X
XThese functions provide access to the raw ethernet for user-level programs.  On
XSuns, they are implemented using NIT(4p) (network interface tap).  While they
Xdo not provide the full functionality of NIT, these functions do run on both
Xthe socket- and streams-based NIT implementations.  On Ultrix systems, they are
Ximplemented using DLI (data link interface).  On Berkeley systems, they are
Ximplemented using the Stanford enetfilter available as user-contributed
Xsoftware in the 4.3 BSD release.
X
XThese functions are not designed to be used for ethernet monitoring, but rather
Xfor programs implementing ethernet protocols such as RARP, or the Ethernet
Xconfiguration test protocol.
X
XIt comes with a manual page, and both a GNU makefile and a regular one.
X
XIf you are on a BSD system with the enetfilter, you will have to create some
Xnew device files before you can build or use this library.  Because there is no
Xway to map between the interface names ("il0", "de0", etc.) used by most
Xprograms and the old enetfilter device names (/dev/enet0, /dev/eneta0, etc.),
Xthis library uses a different convention for enetfilter device names, using
Xdevice files in the /dev/enet/ directory.
X
XTherefore, you should create or link an enetfilter device in /dev/enet for each
Xethernet interface, with names like /dev/enet/il0, /dev/enet/de0, etc.  The
Xminor device numbers for these files will correspond to the order in which they
Xare found by the kernel.  This order is the same as in the config file, except
Xthat devices configured into the kernel but not present are not counted.  You
Xcan look at the kernel startup messages in /usr/adm/messages to see the order
Xof ethernet devices; the ethernet addresses are also printed out there, and you
Xcan check those against the results of the ethertest program here.
X
XIf you have GNU make, you should be able to say "gmake" in this directory, and
Xit will build the library for your system in a subdirectory.  You may want to
Xedit the GNUmake.config file to specify various options (such as installation
Xdirectories, cc vs. gcc, etc.)  Once you are satisfied that it has built
Xcorrectly, you can say "gmake install".
X
XIf you don't have GNU make, you will have to cd to the src subdirectory, and
Xedit the Makefile there to reflect your system configuration.  Once you have
Xdone this, you can say "make" to build the library, and "make install" to
Xinstall it.
X
XIf you encounter bugs, or are interested in porting this library to another
Xethernet access interface, please contact me.
X
XAlexander Dupuy
X480 C.S.B.
XComputer Science Dept.
XColumbia University
XNew York City 10027-6699
X
X<dupuy@cs.columbia.edu>
X!rutgers!cs.columbia.edu!dupuy
X
XThis library can be obtained via anonymous FTP from columbia.edu or
Xcs.columbia.edu, in the file pub/etherlib.tar.Z.
X
END_OF_FILE
if test 2921 -ne `wc -c <'./Instructions'`; then
    echo shar: \"'./Instructions'\" unpacked with wrong size!
fi
# end of './Instructions'
fi
if test -f './SunBugs' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./SunBugs'\"
else
echo shar: Extracting \"'./SunBugs'\" \(1962 characters\)
sed "s/^X//" >'./SunBugs' <<'END_OF_FILE'
XThis is a description of a bug in SunOS 4.0 NIT, which is not fixed in 4.0.3
X
X1016994: Public Summary:
X1016994:	The ifpromisc() routine of net/if.c, which handles
X1016994:	transitions into and out of promiscuous mode by
X1016994:	keeping track of the number of outstanding requests
X1016994:	there are for the mode and calling the interface driver
X1016994:	to change mode on transitions to and from zero
X1016994:	has a bug that causes it to disable promiscuous
X1016994:	mode whenever it is called to disable the mode and
X1016994:	the number of outstanding requests for the mode is
X1016994:	greater than one.
X1016994:	The problem occurs only when there are more than one
X1016994:	concurrent requesters for promiscuous mode for a
X1016994:	particular interface (i.e. run multiple etherfind's
X1016994:	on the same interface in parallel, then terminate
X1016994:	one of the processes).
X1016994: Hook 2:  Needs investigation in release: 4.0.4, 4.0.4c
X
XThis can cause interfaces to go out of promiscuous mode when they shouldn't;
Xpromiscuous mode reception may fail as a result.  This also impacts the
Xreception of multicast addresses with this library, since that is implemented
Xon Suns with promiscuous mode reception and filtering.
X
XThe only workaround seems to be to close all promiscuous mode file descriptors
Xin all processes, then reopen them.  Just setting the IFF_PROMISC bit with a
XSIOCSIFFLAGS ioctl doesn't seem to help.
X
X
X
XThis is a description of a bug in SunOS 4.0.3 NIT.
X
XThe NIT interface now receives broadcast packets sent from the local machine,
Xbut their ethernet source field will sometimes contain a random value.  The
Xpackets as sent out on the ethernet are correct, but the NIT interface
Xsometimes receives them incorrectly.
X
XYou can tell if this bug affects you by running "etherfind -p -arp" and then
Xpinging a nonexistent (or down) host.  If you have the bug, you will see lots
Xof arp packets from strange hosts.  There is no known workaround.
END_OF_FILE
if test 1962 -ne `wc -c <'./SunBugs'`; then
    echo shar: \"'./SunBugs'\" unpacked with wrong size!
fi
# end of './SunBugs'
fi
if test -f './src/Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./src/Makefile'\"
else
echo shar: Extracting \"'./src/Makefile'\" \(3830 characters\)
sed "s/^X//" >'./src/Makefile' <<'END_OF_FILE'
X#
X# makefile for ethernet library
X#
X
X# Compilation variables & flags
X
X#CC = gcc
X
X#
X# Sun-3 floating-point options; replace 68881 with soft or fpa as appropriate
X#
X
X#FLOAT_OPTION = f68881
X
XOPT = -O
XOPTG = -g -O -W
X
XDEFINES = 
XINCLUDES = -I. # -I../enet/4.3
X
X# Listing variables and flags
X
XTROFF = ptroff
XVGRIND = vgrind
X
X
X# Suffix rules
X
X.SUFFIXES: .ps
X
X.c.ps:
X	$(VGRIND) -lC -t $< > $@
X
X.h.ps:
X	$(VGRIND) -lC -t $< > $@
X
X
X# Installation tools
X
XINSTALL=install -c
X
XRANLIB=ranlib
X#RANLIB=ranlib -t
X
X
X# Installation locations
X
XMANDIR = /usr/local/man
XBINDIR = /usr/local/bin
XLIBDIR = /usr/local/lib
XINCDIR = /usr/local/include
X
XCFLAGS = $(OPT) $(DEFINES) $(INCLUDES)
X#CFLAGS = $(OPTG) $(DEFINES) $(INCLUDES)
X
XLINTFLAGS = -bhuxz
X
X
X# Software components
X
XHDRS = ether.h
X
XCSRCS = etheraddr.c etherints.c ethere2a.c ethera2e.c etherarp.c etherlocal.c \
X ethere2ip.c etherip2e.c ethere2h.c etherh2e.c etherhe2e.c
XCOBJS = etheraddr.o etherints.o ethere2a.o ethera2e.o etherarp.o etherlocal.o \
X ethere2ip.o etherip2e.o ethere2h.o etherh2e.o etherhe2e.o
X
X# SunOS 4.0
X#SRCS = $(CSRCS) etherblock.c etherread.c etherreadv.c \
X# nitaddr.c nit4self.c nit4intaddr.c nit4open.c nit4write.c nit4writev.c
X#OBJS = $(COBJS) etherblock.o etherread.o etherreadv.o \
X# nitaddr.o nit4self.o nit4intaddr.o nit4open.o nit4write.o nit4writev.o
X
X# SunOS 3.x
X#SRCS = $(CSRCS) etherblock.c nitaddr.c nit3self.c nit3intaddr.c \
X# nit3open.c nit3read.c nit3readv.c nit3write.c nit3writev.c
X#OBJS = $(COBJS) etherblock.o nitaddr.o nit3self.o nit3intaddr.o \
X# nit3open.o nit3read.o nit3readv.o nit3write.o nit3writev.o
X
X# Ultrix
X#SRCS = $(CSRCS) etherblock.c dliaddr.c dliself.c dliintaddr.c \
X# dliopen.c dliread.c dlireadv.c dliwrite.c dliwritev.c
X#OBJS = $(COBJS) etherblock.o dliaddr.o dliself.o dliintaddr.o \
X# dliopen.o dliread.o dlireadv.o dliwrite.o dliwritev.o
X
X# Stanford enetfilter
X#SRCS = $(CSRCS) etherread.c etherreadv.c enetblock.c enetaddr.c \
X# enetintaddr.c enetself.c enetopen.c enetwrite.c enetwritev.c
X#OBJS = $(COBJS) etherread.o etherreadv.o enetblock.o enetaddr.o \
X# enetintaddr.o enetself.o enetopen.o enetwrite.o enetwritev.o
X
X
XLISTS = etheraddr.ps etherints.ps ethere2a.ps ethera2e.ps etherarp.ps \
X etherlocal.ps ethere2ip.ps etherip2e.ps ethere2h.ps etherh2e.ps etherhe2e.ps \
X etherblock.ps etherread.ps etherreadv.ps nitaddr.ps \
X nit4self.ps nit4intaddr.ps nit4open.ps nit4write.ps nit4writev.ps \
X nit3self.ps nit3intaddr.ps nit3open.ps \
X nit3read.ps nit3readv.ps nit3write.ps nit3writev.ps \
X dliaddr.ps dliself.ps dliintaddr.ps dliopen.ps \
X dliread.ps dlireadv.ps dliwrite.ps dliwritev.ps \
X enetblock.ps enetaddr.ps enetself.ps enetintaddr.ps enetopen.ps \
X enetwrite.ps enetwritev.ps
X
X
X# Default dependency - remake all out of date object files
X
Xdefault: all
X
Xall: libether.a
X
Xlibether.a: $(OBJS)
X	ar curv $@ $(OBJS)
X	ranlib $@
X
Xetheraddr.o: etheraddr.c
X	$(CC) $(CFLAGS) -R -c etheraddr.c
X
Xtest: ethertest
X	./ethertest
X
Xethertest: ethertest.o libether.a
X	$(CC) $(LDFLAGS) -o ethertest ethertest.o libether.a
X
Xethertest.o:
X	$(CC) $(CFLAGS) -c ../tests/ethertest.c
X
Xctp: ctp.o libether.a
X	$(CC) $(LDFLAGS) -o ctp ctp.o libether.a
X
Xctp.o:
X	$(CC) $(CFLAGS) -c ../tests/ctp.c
X
X$(OBJS): $(HDRS)
X
X
X# Fluff test
X
Xlint: $(SRCS) ../tests/ethertest.c
X	-lint $(LINTFLAGS) $(DEFINES) $(INCLUDES) -I. $?
X
X
X# Vgrind formatted listing
X
Xlisting: index $(LISTS) index.ps
X
Xindex.ps: index
X	sort -fu -o index index
X	$(VGRIND) -t -x index > index.ps
X
Xindex: /dev/null
X	ctags -tv $(SRCS) $(HDRS) >> index 2>/dev/null
X
X
X# Utility operations
X
Xclean:
X	rm -f $(OBJS) libether.a ethertest.o ethertest ctp.o ctp
X
Xcleanlists:
X	rm -f $(LISTS) index
X
Xrealclean: clean cleanlists
X
Xinstall: all
X	$(INSTALL) ether.3n $(MANDIR)/man3
X	cd src; $(INSTALL) ether.h $(INCDIR)
X	$(INSTALL) $(SYSTEM)/libether.a $(LIBDIR)/libether.a
X	$(RANLIB) $(LIBDIR)/libether.a
END_OF_FILE
if test 3830 -ne `wc -c <'./src/Makefile'`; then
    echo shar: \"'./src/Makefile'\" unpacked with wrong size!
fi
# end of './src/Makefile'
fi
if test -f './src/dliopen.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./src/dliopen.c'\"
else
echo shar: Extracting \"'./src/dliopen.c'\" \(3045 characters\)
sed "s/^X//" >'./src/dliopen.c' <<'END_OF_FILE'
X/* $Id: dliopen.c,v 2.1 89/10/23 15:42:00 dupuy Exp $ */
X
X#include <sys/param.h>			/* NOFILE */
X#include <sys/socket.h>			/* sockaddr_dl (sockaddr) */
X
X#include <net/if.h>			/* ifdevea */
X#include <netinet/in.h>			/* (ether_header) (in_addr) */
X#include <netinet/if_ether.h>		/* sockaddr_dl (ether_header) */
X#include <netdnet/dli_var.h>		/* sockaddr_dl */
X
X#include <ctype.h>			/* isdigit */
X#include <errno.h>			/* EMFILE */
X
X#include "libether.h"
X
Xether_addr _ether_multi_addrs[NOFILE];
Xstruct sockaddr_dl _ether_sockaddrs[NOFILE];
X
X#define multi_addr (_ether_multi_addrs[fd])
X#define sad (_ether_sockaddrs[fd])
X
X
Xstatic void
Xname_to_devid (devid, name)
Xstruct dli_devid *devid;
Xchar *name;
X{
X    register int i = 0;
X
X    while ((*name != '\0') && (isalpha (name[i]) != 0) && (i < DLI_DEVSIZE))
X    {
X	devid->dli_devname[i] = name[i];
X	i++;
X    }
X
X    devid->dli_devname[i] = '\0';
X
X    devid->dli_devnumber = atoi (&name[i]);
X}
X
X
X/*
X * Returns file descriptor for ethernet device by name ("de0", "qe0", etc.).
X * If name is NULL, uses primary ethernet interface.  Will only receive
X * packets of type specified.  Will receive packets for the ethernet address
X * specified, or local ethernet address if NULL.  If there is an error,
X * returns (-1) and the appropriate value is left in errno.  Normal return
X * status zero. Requires superuser privilege.
X */
X
Xint
Xether_open (name, type, address)
Xchar *name;
Xunsigned type;
Xether_addr *address;
X{
X    int fd;
X    char **interfaces;
X    int saved_errno;			/* close seems to blow errno away */
X
X    if (name == 0)
X    {					/* get default ethernet interface */
X	interfaces = ether_interfaces ();
X	if (interfaces == 0 || *interfaces == 0)
X	    return (-1);
X
X	name = *interfaces;		/* just use the first name in list */
X    }
X
X    if ((fd = socket (AF_DLI, SOCK_DGRAM, DLPROTO_DLI)) < 0)
X    {
X#ifdef DEBUG
X	perror ("ether_open: socket");
X#endif
X	return (-1);
X    }
X
X    if (fd >= NOFILE)			/* not worth making it work here */
X    {
X	(void) close (fd);
X	errno = EMFILE;
X	return (-1);
X    }
X
X    if (type > ETHER_MAXTYPE)
X    {
X	(void) close (fd);
X	errno = EINVAL;
X	return (-1);
X    }
X
X    bzero (&sad, sizeof (sad));
X    sad.dli_family = AF_DLI;
X    sad.dli_substructype = DLI_ETHERNET;
X    name_to_devid (&sad.dli_device, name);
X    sad.choose_addr.dli_eaddr.dli_ioctlflg = DLI_EXCLUSIVE;
X    sad.choose_addr.dli_eaddr.dli_protype = type;
X
X    if (bind (fd, (struct sockaddr *) &sad, sizeof (sad)) != 0)
X    {
X	saved_errno = errno;
X#ifdef DEBUG
X	perror ("ether_open: bind");
X#endif
X	(void) close (fd);
X	errno = saved_errno;
X	return (-1);
X    }
X
X    if (address != 0)			/* a multicast address */
X    {
X	if (setsockopt (fd, DLPROTO_DLI, DLI_MULTICAST, (char *) address,
X			sizeof (ether_addr)) != 0)
X	{
X	    saved_errno = errno;
X#ifdef DEBUG
X	    perror ("ether_open: setsockopt");
X#endif
X	    (void) close (fd);
X	    errno = saved_errno;
X	    return (-1);
X	}
X	multi_addr = *address;
X    }
X    else
X	multi_addr = ether_bcast_addr;
X
X    sad.choose_addr.dli_eaddr.dli_ioctlflg = 0;
X
X    return (fd);
X}
END_OF_FILE
if test 3045 -ne `wc -c <'./src/dliopen.c'`; then
    echo shar: \"'./src/dliopen.c'\" unpacked with wrong size!
fi
# end of './src/dliopen.c'
fi
if test -f './src/enetopen.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./src/enetopen.c'\"
else
echo shar: Extracting \"'./src/enetopen.c'\" \(5128 characters\)
sed "s/^X//" >'./src/enetopen.c' <<'END_OF_FILE'
X/* $Id: enetopen.c,v 2.1 89/10/23 15:42:14 dupuy Exp $ */
X
X#include <strings.h>			/* strncpy */
X
X#include <sys/file.h>			/* O_RDWR */
X#include <sys/types.h>			/* enfilter (u_char) */
X#include <sys/socket.h>			/* IFNAMSIZ (sockaddr) */
X#include <sys/ioctl.h>			/* ioctl */
X
X#include <net/if.h>			/* IFNAMSIZ */
X#include <net/enet.h>			/* enfilter */
X
X#include <netinet/in.h>			/* htons */
X
X#include <errno.h>			/* EMFILE/EINVAL */
X
Xextern int errno;
X
X#include "libether.h"
X
X#ifndef ENET_DEVDIR
X#define ENET_DEVDIR "/dev/enet/"
X#endif
X
X#define packetfilt	enfilter
X#define Pf_Priority	enf_Priority
X#define Pf_FilterLen	enf_FilterLen
X#define Pf_Filter	enf_Filter
X
X
Xstatic ether_addr promiscuous;
X
Xunsigned _ether_types[FD_SETSIZE];
X
X#define ether_type (_ether_types[fd])
X
X#ifdef __STDC__
Xvoid _ether_newaddr (int fd);
X#else
Xvoid _ether_newaddr ();
X#endif
X
X
Xstatic int
Xeiocsetf (fd, filter)
Xint fd;
Xstruct packetfilt *filter;
X{
X    int saved_errno;
X    filter->Pf_Priority = 1;		/* should be < 2 */
X
X    if (ioctl (fd, EIOCSETF, (char *) filter) < 0)
X    {
X	saved_errno = errno;
X	(void) close (fd);
X	errno = saved_errno;
X	return (-1);
X    }
X
X    return (0);
X}
X
X/*
X * Returns file descriptor for ethernet device by name ("ie0", "le0", etc.).
X * If name is NULL, uses primary ethernet interface.  Will only receive
X * packets of type specified.  Will receive packets for the ethernet address
X * specified, or local ethernet address if NULL.  If there is an error,
X * returns (-1) and the appropriate value is left in errno.  Normal return
X * status zero. Requires superuser privilege.
X */
X
Xint
Xether_open (name, type, address)
Xchar *name;
Xunsigned type;
Xether_addr *address;
X{
X    int fd;
X    struct packetfilt filter;
X    unsigned short *fptr = 0;
X    char **interfaces;
X    char pathname[sizeof (ENET_DEVDIR) + IFNAMSIZ];
X#if !defined(MULTICAST) && defined(PROMISCUOUS)
X    register int i;
X#endif
X
X    if (name == 0)			/* get default ethernet interface */
X    {
X	interfaces = ether_interfaces ();
X	if (interfaces == 0 || *interfaces == 0)
X	    return (-1);
X
X	name = *interfaces;		/* just use the first name in list */
X    }
X
X    (void) strcpy (pathname, ENET_DEVDIR);
X    (void) strncat (pathname, name, IFNAMSIZ);
X
X    if ((fd = open (pathname, O_RDWR)) < 0)
X    {
X#ifdef DEBUG
X	perror (pathname);
X#endif
X	return (-1);
X    }
X
X    if (fd >= FD_SETSIZE)		/* not worth making it work here */
X    {
X	(void) close (fd);
X	errno = EMFILE;
X	return (-1);
X    }
X
X    /* set up filter */
X
X    if (type != ETHER_ALLTYPES)		/* hack for NIT features */
X    {
X	if (type > ETHER_MAXTYPE)
X	{
X	    (void) close (fd);
X	    errno = EINVAL;
X	    return (-1);
X	}
X
X
X	fptr = &filter.Pf_Filter[0];
X
X	*fptr++ = ENF_PUSHWORD + ETHER_TYPE / sizeof (short);
X	*fptr++ = ENF_PUSHLIT | ENF_EQ;
X	*fptr++ = htons ((u_short) type);
X
X	filter.Pf_FilterLen = fptr - &filter.Pf_Filter[0];
X
X	if (eiocsetf (fd, &filter) < 0)
X	    return (-1);
X    }
X
X    if (address != 0)
X    {
X	if (ether_cmp (address, &promiscuous))
X	{
X#if !defined(MULTICAST) && defined(PROMISCUOUS)
X	    ether_addr local_addr;
X#endif
X	    if (!ETHER_MCAST (address))
X	    {
X#ifdef DEBUG
X		(void) printf ("rejecting non-multicast address argument\n");
X#endif
X		(void) close (fd);
X		errno = EINVAL;
X		return (-1);
X	    }
X
X#ifdef MULTICAST
X	    /* #error not clear how to set multicast addresses */
X	    exit (-1);			/* die die die */
X#else
X#ifdef PROMISCUOUS
X
X	    /*
X	     * Enable address matching filter before we go into promiscuous
X	     * mode.
X	     */
X
X	    (void) ether_address (fd, &local_addr);
X
X	    fptr = &filter.Pf_Filter[0];
X
X	    if (type != ETHER_ALLTYPES)	/* hack for NIT features */
X	    {
X		*fptr++ = ENF_PUSHWORD + ETHER_TYPE / sizeof (short);
X		*fptr++ = ENF_PUSHLIT;
X		*fptr++ = htons (type);	/* should be in host order */
X		*fptr++ = ENF_CAND;
X	    }
X
X	    for (i = 0; i < 3; i++)	/* compare addresses in 3 shorts */
X	    {
X		*fptr++ = ENF_PUSHWORD + ETHER_DST / sizeof (short) + i;
X		*fptr++ = ENF_PUSHLIT | ENF_EQ;
X		*fptr++ = ((short *) address)[i];
X		*fptr++ = ENF_PUSHWORD + ETHER_DST / sizeof (short) + i;
X		*fptr++ = ENF_PUSHLIT | ENF_EQ;
X		*fptr++ = ((short *) &ether_bcast_addr)[i];
X		*fptr++ = ENF_OR;
X		*fptr++ = ENF_PUSHWORD + ETHER_DST / sizeof (short) + i;
X		*fptr++ = ENF_PUSHLIT | ENF_EQ;
X		*fptr++ = ((short *) &local_addr)[i];
X		*fptr++ = ENF_CNOR;
X	    }
X
X	    filter.Pf_FilterLen = fptr - &filter.Pf_Filter[0];
X
X	    if (eiocsetf (fd, &filter) < 0)
X		return (-1);
X#else
X#ifdef DEBUG
X	    (void) printf ("rejecting multicast address argument\n");
X#endif
X	    (void) close (fd);
X	    errno = EINVAL;
X	    return (-1);
X
X#endif					/* PROMISCUOUS */
X
X#endif					/* MULTICAST */
X
X	}
X
X#ifdef MULTICAST
X	else				/* only promiscuous if requested */
X# endif
X	{				/* go into promiscuous mode */
X
X#ifdef PROMISCUOUS
X	    /* #error not clear how to set promiscuous mode */
X	    exit (-1);			/* die die die */
X#else
X#ifdef DEBUG
X	    (void) printf ("rejecting promiscuous address argument\n");
X#endif
X	    (void) close (fd);
X	    errno = EINVAL;
X	    return (-1);
X
X#endif					/* PROMISCUOUS */
X
X	}
X    }
X
X    _ether_newaddr (fd);
X    ether_type = type;
X    return (fd);
X}
END_OF_FILE
if test 5128 -ne `wc -c <'./src/enetopen.c'`; then
    echo shar: \"'./src/enetopen.c'\" unpacked with wrong size!
fi
# end of './src/enetopen.c'
fi
if test -f './src/ether.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./src/ether.h'\"
else
echo shar: Extracting \"'./src/ether.h'\" \(3510 characters\)
sed "s/^X//" >'./src/ether.h' <<'END_OF_FILE'
X/* $Id: ether.h,v 2.2 89/10/23 15:42:19 dupuy Exp $ */
X
X/* Interface definitions for ethernet access library */
X
Xtypedef union etheraddr
X{
X    unsigned char bytes[6];		/* byteorder safe initialization */
X    unsigned short shorts[3];		/* force 2-byte alignment */
X}
X	  ether_addr;
X
Xtypedef struct etherpacket
X{
X    ether_addr dest;
X    ether_addr src;
X    unsigned char type[2];		/* in network byte order! */
X    unsigned short pktlen;		/* length of pktbuf ONLY */
X    char *pktbuf;
X}
X	    ether_packet;
X
Xtypedef struct ethervec
X{
X    ether_addr dest;
X    ether_addr src;
X    unsigned char type[2];		/* in network byte order! */
X    unsigned short iovcnt;		/* number of iovec to use */
X    struct iovec *iov;			/* ptr to array of iovec */
X}
X	 ether_vec;
X
X#ifndef __ETHER_BCAST_ADDR__
Xextern ether_addr ether_bcast_addr;
X#endif
X
X#ifdef __STDC__
X
Xint ether_open (char *name, unsigned type, ether_addr * address);
X
Xether_addr *ether_address (int fd, ether_addr * address);
X
Xether_addr *ether_intfaddr (char *intf, ether_addr * address);
X
Xchar **ether_interfaces (void);
X
Xint ether_write (int fd, ether_packet * packet);
X
Xint ether_writev (int fd, ether_vec * packet);
X
Xint ether_read (int fd, ether_packet * packet);
X
Xint ether_readv (int fd, ether_vec * packet);
X
Xint ether_blocking (int fd, int state);
X
Xint ether_send_self (int fd);
X
Xint ether_mcast_self (int fd);
X
Xint ether_bcast_self (int fd);
X
Xchar *ether_ntoa (ether_addr *);
X
Xether_addr *ether_aton (char *);
X
X#ifdef __GNUC__
X
X/*
X * Avoid stupid warnings if structs aren't defined
X */
X
Xtypedef struct in_addr *_ether_NoNsEnSe;
Xtypedef struct hostent *_ether_nOnSeNsE;
X
X#endif
X
Xchar *ether_e2a (ether_addr *, char *);
X
Xether_addr *ether_a2e (char *, ether_addr *);
X
Xstruct in_addr *ether_e2ip (ether_addr *, struct in_addr *);
X
Xether_addr *ether_ip2e (struct in_addr *, ether_addr *);
X
Xchar *ether_e2host (ether_addr *, char *);
X
Xether_addr *ether_host2e (char *, ether_addr *);
X
Xether_addr *ether_hostent2e (struct hostent *, ether_addr *);
X
X#else
X
Xint ether_open ();
Xether_addr *ether_address ();
Xether_addr *ether_intfaddr ();
Xchar **ether_interfaces ();
Xint ether_write ();
Xint ether_writev ();
Xint ether_read ();
Xint ether_readv ();
Xint ether_blocking ();
Xint ether_send_self ();
Xint ether_mcast_self ();
Xint ether_bcast_self ();
X
Xchar *ether_ntoa ();
Xether_addr *ether_aton ();
Xchar *ether_e2a ();
Xether_addr *ether_a2e ();
Xstruct in_addr *ether_e2ip ();
Xether_addr *ether_ip2e ();
Xchar *ether_e2host ();
Xether_addr *ether_host2e ();
Xether_addr *ether_hostent2e ();
X
X#endif
X
X#undef ether_cmp			/* lose def from netinet/if_ether.h */
X
X#define ether_cmp(addr1,addr2) \
X ((addr1)->shorts[0] != (addr2)->shorts[0] \
X  || (addr1)->shorts[1] != (addr2)->shorts[1] \
X  || (addr1)->shorts[2] != (addr2)->shorts[2])
X
X#define ETHERSTRLEN 18			/* max length of "xx:xx:xx:xx:xx:xx" */
X
X#ifdef NOFILE				/* i.e. we have included sys/param.h */
X#ifndef MAXHOSTNAMELEN			/* but MAXHOSTNAMELEN still isnt set */
X#define MAXHOSTNAMELEN 64
X#endif
X#endif
X
X/* should be defined in terms of ether_packet struct; need offsetof() macro */
X
X#define ETHER_DST	0
X#define ETHER_SRC	6
X#define ETHER_TYPE	12
X#define ETHER_PKT	14
X#define ETHER_MIN	46
X#define ETHER_MAX	1500
X
X#define ETHER_MINTYPE	0x5DD		/* lowest protocol not valid IEEE802 */
X#define ETHER_MAXTYPE	0xFFFF		/* largest possible protocol */
X
X#define ETHER_MCAST(addr) (((unsigned char *) (addr))[0] & 0x01)
X
X#ifdef NT_ALLTYPES
X#define ETHER_ALLTYPES NT_ALLTYPES
X#else
X#define ETHER_ALLTYPES ((unsigned) -1)
X#endif
END_OF_FILE
if test 3510 -ne `wc -c <'./src/ether.h'`; then
    echo shar: \"'./src/ether.h'\" unpacked with wrong size!
fi
# end of './src/ether.h'
fi
if test -f './src/etherarp.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./src/etherarp.c'\"
else
echo shar: Extracting \"'./src/etherarp.c'\" \(4253 characters\)
sed "s/^X//" >'./src/etherarp.c' <<'END_OF_FILE'
X/* $Id: etherarp.c,v 2.1 89/10/23 15:42:24 dupuy Exp $ */
X
X#include <sys/types.h>			/* arptab (u_short) */
X#include <sys/socket.h>			/* arptab (sockaddr) */
X#include <net/if.h>			/* arptab (ifnet) */
X#ifdef _SOCKET_				/* 4.0 system? */
X#include <net/if_arp.h>			/* arptab (arphdr) */
X#endif
X#include <netinet/in.h>			/* in_addr */
X#include <netinet/if_ether.h>		/* arptab */
X
X#include <sys/file.h>			/* O_RDONLY */
X#include <nlist.h>			/* nlist */
X
X#include "libether.h"
X
X/*
X * This only understands IP ARP entries.  Chaos, Appletalk, etc. are unknown.
X * Standard kernels don't keep arp tables for those protocols anyhow.
X */
X
Xstruct nlist nl[] = {
X#define	X_ARPTAB	0
X    {"_arptab"},
X#define	X_ARPTAB_SIZE	1
X    {"_arptab_size"},
X    {""},
X};
X
X#ifndef KERNEL_FILENAME
X#define KERNEL_FILENAME "/vmunix"
X#endif
X
X#ifndef KMEM_FILENAME
X#define KMEM_FILENAME "/dev/kmem"
X#endif
X
Xstatic int
Xkmem_read (fd, addr, buf, nbytes)
Xint fd;
Xunsigned long addr;
Xchar *buf;
Xunsigned nbytes;
X{
X    extern long lseek ();
X
X    return (lseek (fd, (long) addr, L_SET) == -1L
X	    || read (fd, buf, (int) nbytes) < nbytes);
X}
X
Xstatic int
Xreadarptable (atp)
Xstruct arptab **atp;
X{
X    int kmem;
X    int arptab_size;
X    int bytes;
X    struct arptab *at;
X
X    if (atp == 0)
X	return (-1);
X
X    if ((kmem = open (KMEM_FILENAME, O_RDONLY)) < 0)
X	return (-1);
X
X    /*
X     * Despite what Ultrix lint says, nlist _does_ return a value
X     */
X
X    if (nlist (KERNEL_FILENAME, nl) != 0)
X	return (-1);
X
X#if defined (sun386) || defined (COFF)
X    if (nl[X_ARPTAB_SIZE].n_value == 0)
X#else
X    if (nl[X_ARPTAB_SIZE].n_type == 0)
X#endif
X	return (-1);
X
X    if (kmem_read (kmem, nl[X_ARPTAB_SIZE].n_value,
X		   (char *) &arptab_size, (unsigned) sizeof (arptab_size)))
X	return (-1);
X
X    if (arptab_size <= 0 || arptab_size > 10000)
X	return (-1);
X
X    bytes = arptab_size * sizeof (struct arptab);
X
X    if (*atp == 0)
X	*atp = at = (struct arptab *) malloc ((unsigned) bytes);
X    else
X	at = *atp;
X
X    if (at == 0)
X	return (0);			/* may be able to get memory later */
X
X    if (kmem_read (kmem, nl[X_ARPTAB].n_value, (char *) at, (unsigned) bytes))
X	return (-1);
X
X    (void) close (kmem);
X
X    return (arptab_size);
X}
X
X/*
X * This code is derived from "src/etc/arp.c"
X *
X * Copyright (c) 1984 Regents of the University of California. All rights
X * reserved.
X *
X * This code is derived from software contributed to Berkeley by Sun
X * Microsystems, Inc.
X *
X * Redistribution and use in source and binary forms are permitted provided
X * that the above copyright notice and this paragraph are duplicated in all
X * such forms and that any documentation, advertising materials, and other
X * materials related to such distribution and use acknowledge that the software
X * was developed by the University of California, Berkeley.  The name of the
X * University may not be used to endorse or promote products derived from this
X * software without specific prior written permission. THIS SOFTWARE IS
X * PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
X * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS
X * FOR A PARTICULAR PURPOSE.
X */
X
Xint
X_ether_arpscan (addr, ipaddr)
Xether_addr *addr;
Xstruct in_addr *ipaddr;
X{
X    static int arptab_size = 0;		/* kernel arptab is fixed size */
X    static struct arptab *arptab;
X    struct arptab *at;
X    int i;
X    int again = 0;
X
X    if (arptab_size == 0)
X	arptab_size = again = readarptable (&arptab);
X
X    if (arptab_size <= 0)
X	return (0);			/* no luck reading arptab */
X
X    while (1)
X    {
X	for (i = arptab_size, at = arptab; i-- > 0; at++)
X	{
X	    if (at->at_iaddr.s_addr == 0 || at->at_flags == 0)
X		continue;
X
X	    if ((at->at_flags & ATF_COM) == 0)
X		continue;
X
X#ifdef sun				/* sun defines at_enaddr as struct */
X	    if (!bcmp ((char *) &at->at_enaddr, (char *) addr, sizeof (*addr)))
X#else
X	    if (bcmp ((char *) at->at_enaddr, (char *) addr, sizeof (*addr))
X		== 0)
X#endif
X	    {
X		*ipaddr = at->at_iaddr;
X		return (1);
X	    }
X	}
X
X	if (again)
X	    return (0);
X	else				/* try again with current table */
X	    again = readarptable (&arptab);
X    }
X
X    /* NOTREACHED */
X}
X
X#ifdef RARP
X
Xint
X_ether_rarpprobe (addr, ipaddr)
Xether_addr *addr;
Xstruct in_addr *ipaddr;
X{
X    return (0);
X}
X
X#endif
END_OF_FILE
if test 4253 -ne `wc -c <'./src/etherarp.c'`; then
    echo shar: \"'./src/etherarp.c'\" unpacked with wrong size!
fi
# end of './src/etherarp.c'
fi
if test -f './src/ethere2h.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./src/ethere2h.c'\"
else
echo shar: Extracting \"'./src/ethere2h.c'\" \(2461 characters\)
sed "s/^X//" >'./src/ethere2h.c' <<'END_OF_FILE'
X/* $Id: ethere2h.c,v 2.1 89/10/23 15:42:30 dupuy Exp $ */
X
X#include <sys/param.h>			/* MAXHOSTNAMELEN */
X#include <sys/socket.h>			/* AF_INET */
X#include <netinet/in.h>			/* in_addr */
X
X#include <netdb.h>			/* hostent */
X#include <strings.h>			/* strncpy */
X
X#include "libether.h"
X
Xstatic char *
Xip2host (addr, hname)
Xstruct in_addr *addr;
Xchar *hname;
X{
X#ifdef lint
X    char *sprintf ();
X#endif
X    struct hostent *host;
X
X    /*
X     * Unfortunately, gethostbyaddr is not reentrant.  It should be.
X     */
X
X    if (host = gethostbyaddr ((char *) addr, sizeof (struct in_addr), AF_INET))
X	(void) strncpy (hname, host->h_name, MAXHOSTNAMELEN);
X    else				/* use dotted-quad notation */
X	(void) sprintf (hname, "[%d.%d.%d.%d]",
X			(addr->s_addr >> 24) & 0xff,
X			(addr->s_addr >> 16) & 0xff,
X			(addr->s_addr >> 8) & 0xff,
X			addr->s_addr & 0xff);
X
X    return (hname);
X}
X
Xchar *
Xether_e2host (addr, hname)
Xether_addr *addr;
Xchar *hname;
X{
X    struct in_addr ipaddr;
X    int allocated = 0;
X
X    if (hname == NULL)
X    {
X	hname = (char *) malloc (MAXHOSTNAMELEN);
X	allocated++;
X    }
X
X    if (hname == NULL)
X	return (NULL);
X
X#ifdef ETHERDB
X    if (ether_ntohost (hname, addr) == 0)
X	return (hname);
X#endif
X
X    /*
X     * At this point we would like to ioctl the arp table and see if we
X     * already have an entry for this ethernet address.	 But the arp table is
X     * hashed by protocol address, not by ethernet address, so we have to
X     * grovel though /dev/kmem and look at all the entries.  And after that,
X     * we may not find an entry for the ethernet address anyhow.
X     */
X
X    if (_ether_arpscan (addr, &ipaddr))
X	return (ip2host (&ipaddr, hname));
X
X    /*
X     * Since the kernel doesn't keep an entry for the local interfaces in the
X     * arp table, we also check the ethernet addresses for each of those
X     * looking for a match.
X     */
X
X    if (_ether_localif (addr, &ipaddr))
X	return (ip2host (&ipaddr, hname));
X
X#ifdef RARP
X
X    /*
X     * Now the only alternative left is to use RARP (via ether_open, etc.) to
X     * try to get the IP address.  Unfortunately, most machines won't RARP for
X     * themselves, so this isn't terribly useful either.  Especially since we
X     * probably need superuser privilege to call ether_open!
X     */
X
X    if (_ether_rarpprobe (addr, &ipaddr))
X	return (ip2host (&ipaddr, hname));
X#endif
X
X    if (allocated)			/* sigh, dispose it */
X	(void) free (hname);
X
X    return (NULL);			/* too bad, we failed */
X}
END_OF_FILE
if test 2461 -ne `wc -c <'./src/ethere2h.c'`; then
    echo shar: \"'./src/ethere2h.c'\" unpacked with wrong size!
fi
# end of './src/ethere2h.c'
fi
if test -f './src/ethere2ip.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./src/ethere2ip.c'\"
else
echo shar: Extracting \"'./src/ethere2ip.c'\" \(3364 characters\)
sed "s/^X//" >'./src/ethere2ip.c' <<'END_OF_FILE'
X/* $Id: ethere2ip.c,v 2.1 89/10/23 15:42:32 dupuy Exp $ */
X
X#include <sys/param.h>			/* MAXHOSTNAMELEN */
X#include <sys/socket.h>			/* AF_INET */
X#include <netinet/in.h>			/* in_addr */
X
X#include <netdb.h>			/* hostent */
X
X#include "libether.h"
X
Xstruct in_addr *
Xether_e2ip (addr, ipaddr)
Xether_addr *addr;
Xstruct in_addr *ipaddr;
X{
X#ifdef ETHERDB
X    char hname[MAXHOSTNAMELEN];
X    struct hostent *host;
X#endif
X    int allocated = 0;
X
X    if (ipaddr == NULL)
X    {
X	ipaddr = (struct in_addr *) malloc (sizeof (struct in_addr));
X	allocated++;
X    }
X
X    if (ipaddr == NULL)
X	return (NULL);
X
X#ifdef ETHERDB
X    if (ether_ntohost (hname, addr) == 0)
X    {
X
X	/*
X	 * Unfortunately, gethostbyname is not reentrant.  It should be.
X	 */
X
X	if ((host = gethostbyname (hname)) && host->h_addrtype == AF_INET)
X	{
X	    ether_addr arpaddr;
X	    struct in_addr haddr;
X	    int arpsucceeded = 0;
X
X	    /*
X	     * We have the answer(s), but they may be wrong.  Check with ARP.
X	     */
X
X#ifdef h_addr				/* we have a list */
X	    char **hlist;
X
X	    for (hlist = host->h_addr_list; *hlist != NULL; hlist++)
X	    {
X		bcopy (*hlist, (char *) &haddr, sizeof (haddr));
X#else
X		bcopy (host->h_addr, (char *) &haddr, sizeof (haddr));
X#endif
X		if (ether_ip2e (&haddr, &arpaddr))
X		{
X		    if (ether_cmp (&arpaddr, addr) == 0)
X		    {
X			*ipaddr = haddr;
X			return (ipaddr);
X		    }
X#ifdef DEBUG				/* warn that etherdb is incorrect */
X		    else
X		    {
X			char ethera[ETHERSTRLEN];
X			char etherb[ETHERSTRLEN];
X			
X			(void) printf ("bad ether address for %s: %s/%s\n",
X				       host->h_name,
X				       ether_e2a (addr, ethera),
X				       ether_e2a (&arpaddr, etherb));
X		    }
X#endif
X		    arpsucceeded++;
X		}
X#ifdef h_addr
X	    }
X#endif
X	    if (!arpsucceeded)
X	    {
X
X		/*
X		 * We couldn't ARP the address(es).  So we'll use the primary.
X		 */
X		bcopy (host->h_addr, (char *) ipaddr, sizeof (*ipaddr));
X		return (ipaddr);
X	    }
X	}
X    }
X#endif
X
X    /*
X     * While the ethers db may be wrong, proxy ARP makes using the ARP table
X     * even more prone to error.  If RARP were better supported by more
X     * machines, we would do well to use it before this.
X     */
X
X    /*
X     * At this point we would like to ioctl the arp table and see if we
X     * already have an entry for this ethernet address.	 But the arp table is
X     * hashed by protocol address, not by ethernet address, so we have to
X     * grovel though /dev/kmem and look at all the entries.  And after that,
X     * we may not find an entry for the ethernet address anyhow.
X     */
X
X    if (_ether_arpscan (addr, ipaddr))
X	return (ipaddr);
X
X    /*
X     * Since the kernel doesn't keep an entry for the local interfaces in the
X     * arp table, we also check the ethernet addresses for each of those
X     * looking for a match.
X     */
X
X    if (_ether_localif (addr, ipaddr))
X	return (ipaddr);
X
X#ifdef RARP
X
X    /*
X     * Now the only alternative left is to use RARP (via ether_open, etc.) to
X     * try to get the IP address.  Unfortunately, most machines won't RARP for
X     * themselves, so this isn't terribly useful either.  Especially since we
X     * probably need superuser privilege to call ether_open!
X     */
X
X    if (_ether_rarpprobe (addr, ipaddr))
X	return (ipaddr);
X#endif
X
X    if (allocated)			/* sigh, dispose it */
X	(void) free ((char *) ipaddr);
X
X    return (NULL);			/* too bad, we failed */
X}
END_OF_FILE
if test 3364 -ne `wc -c <'./src/ethere2ip.c'`; then
    echo shar: \"'./src/ethere2ip.c'\" unpacked with wrong size!
fi
# end of './src/ethere2ip.c'
fi
if test -f './src/etherh2e.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./src/etherh2e.c'\"
else
echo shar: Extracting \"'./src/etherh2e.c'\" \(1936 characters\)
sed "s/^X//" >'./src/etherh2e.c' <<'END_OF_FILE'
X/* $Id: etherh2e.c,v 2.1 89/10/24 17:53:15 dupuy Exp $ */
X
X#include <sys/types.h>			/* in_addr (u_short) */
X#include <netinet/in.h>			/* in_addr */
X
X#include <netdb.h>			/* hostent */
X#include <errno.h>			/* ENOENT */
X
Xextern int errno;
X
X#include "libether.h"
X
X/*
X * derived from ethertools/htoea.c
X *
X * Copyright (c) 1988 Philip L. Budne and The Trustees of Boston University
X * All Rights Reserved
X *
X * Permission is granted to any individual or institution to use, copy, or
X * redistribute this software so long as it is not sold for profit, provided
X * that this notice and the original copyright notices are retained.  Boston
X * University makes no representations about the suitability of this software
X * for any purpose.  It is provided "as is" without express or implied
X * warranty.
X */
X
Xether_addr *
Xether_host2e (hname, addr)
Xchar *hname;
Xether_addr *addr;
X{
X    int allocated = 0;
X    struct in_addr ipaddr;
X    struct hostent *host;
X    unsigned long inet_addr ();
X
X    if (addr == 0)
X    {
X	addr = (ether_addr *) malloc (sizeof (ether_addr));
X	allocated++;
X    }
X
X    if (addr == 0)
X	return (0);
X
X    if (ether_a2e (hname, addr))	/* try ascii ethernet address first */
X	return (addr);
X
X    if ((ipaddr.s_addr = inet_addr (hname)) != (unsigned) -1)
X    {
X	if (ether_ip2e (&ipaddr, addr))
X	    return (addr);		/* dotted quad notation ok too */
X    }
X
X#ifdef ETHERDB
X
X    /*
X     * This answer may be wrong, but since the ethers DB may contain non-IP or
X     * MAC-level devices, it's hard to really check.
X     */
X    if (ether_hostton (hname, addr) == 0)
X	return (addr);
X#endif ETHERDB
X
X    /*
X     * Unfortunately, gethostbyname is not reentrant.  It should be.
X     */
X
X    if ((host = gethostbyname (hname)) != 0)
X    {
X	if (ether_hostent2e (host, addr))
X	    return (addr);
X    }
X    else
X	errno = ENOENT;			/* not quite the right error message */
X
X    if (allocated)
X	(void) free ((char *) addr);
X    return (0);
X}
END_OF_FILE
if test 1936 -ne `wc -c <'./src/etherh2e.c'`; then
    echo shar: \"'./src/etherh2e.c'\" unpacked with wrong size!
fi
# end of './src/etherh2e.c'
fi
if test -f './src/etherhe2e.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./src/etherhe2e.c'\"
else
echo shar: Extracting \"'./src/etherhe2e.c'\" \(2146 characters\)
sed "s/^X//" >'./src/etherhe2e.c' <<'END_OF_FILE'
X/* $Id: etherhe2e.c,v 2.1 89/10/24 17:53:20 dupuy Exp $ */
X
X#include <sys/types.h>			/* in_addr (u_short) */
X#include <sys/socket.h>			/* AF_INET */
X#include <netinet/in.h>			/* in_addr */
X
X#include <netdb.h>			/* hostent */
X#include <errno.h>			/* EAFNOSUPPORT */
X
Xextern int errno;
X
X#include "libether.h"
X
X/*
X * derived from ethertools/hetoea.c
X *
X * Copyright (c) 1988 Philip L. Budne and The Trustees of Boston University
X * All Rights Reserved
X *
X * Permission is granted to any individual or institution to use, copy, or
X * redistribute this software so long as it is not sold for profit, provided
X * that this notice and the original copyright notices are retained.  Boston
X * University makes no representations about the suitability of this software
X * for any purpose.  It is provided "as is" without express or implied
X * warranty.
X */
X
Xether_addr *
Xether_hostent2e (host, addr)
Xstruct hostent *host;
Xether_addr *addr;
X{
X    char **hlist;
X    int allocated = 0;
X
X    if (addr == 0)
X    {
X	addr = (ether_addr *) malloc (sizeof (ether_addr));
X	allocated++;
X    }
X
X#if ETHERDB
X    if (ether_hostton (host->h_name, addr) == 0)
X	return (addr);			/* official name worked */
X
X    for (hlist = host->h_aliases; *hlist != 0; hlist++)
X	if (ether_hostton (*hlist, addr) == 0)
X	    return (addr);
X#endif
X
X    /*
X     * Try to resolve the IP addresses if possible.  We would try this first
X     * if proxy ARP didn't cause such confusion.
X     */
X
X    if (host->h_addrtype == AF_INET)
X    {
X	struct in_addr haddr;
X	int saved_errno = 0;
X
X#ifdef h_addr				/* we have a list */
X	for (hlist = host->h_addr_list; *hlist != 0; hlist++)
X	{
X	    bcopy (*hlist, (char *) &haddr, sizeof (haddr));
X#else
X	    bcopy (host->h_addr, (char *) &haddr, sizeof (haddr));
X#endif
X	    if (ether_ip2e (&haddr, addr))
X		return (addr);
X	    else if (saved_errno == 0)
X		saved_errno = errno;
X	    else if (errno == EHOSTDOWN)
X		saved_errno = errno;
X#ifdef h_addr
X	}
X#endif
X	errno = saved_errno;		/* restore "best" error message */
X    }
X    else
X	errno = EAFNOSUPPORT;		/* not quite the right error message */
X
X    if (allocated)
X	free ((char *) addr);
X
X    return (0);
X}
END_OF_FILE
if test 2146 -ne `wc -c <'./src/etherhe2e.c'`; then
    echo shar: \"'./src/etherhe2e.c'\" unpacked with wrong size!
fi
# end of './src/etherhe2e.c'
fi
if test -f './src/etherints.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./src/etherints.c'\"
else
echo shar: Extracting \"'./src/etherints.c'\" \(2675 characters\)
sed "s/^X//" >'./src/etherints.c' <<'END_OF_FILE'
X/* $Id: etherints.c,v 2.0 89/10/20 19:02:24 dupuy Exp $ */
X
X#include <strings.h>			/* strcmp */
X
X#include <sys/types.h>			/* AF_INET (u_char) */
X#include <sys/socket.h>			/* AF_INET */
X#include <net/if.h>			/* IFNAMSIZ */
X#ifdef _SOCKET_				/* 4.0 system? */
X#include <sys/sockio.h>			/* SIOCGIFCONF */
X#else
X#endif
X#include <sys/ioctl.h>			/* ioctl */
X
X#include "libether.h"
X
Xstatic char checked;			/* boolean flag */
X
Xstatic char *result[MAXNUMIF];
Xstatic char names[MAXNUMIF * IFNAMSIZ];
X#ifdef sun
Xstatic char *validname[] = {"le", "ie", "ec", 0};
X
X#endif
X#ifdef vax
Xstatic char *validname[] = {"de", "ec", "ex", "il", "ni", "qe", "se", 0};
X
X#endif
X#ifdef mips
Xstatic char *validname[] = {"ni", "qe", "se", 0};
X
X#endif
X
X
Xshort _ether_ifindex[MAXNUMIF];		/* used by _ether_localif() */
Xstruct ifconf _ether_ifconf;		/* used by _ether_localif() */
Xstatic char cbuf[MAXNUMIF * sizeof (struct ifreq)];
X
X/*
X * Returns an array of strings (with last element 0) each entry of which is an
X * ethernet interface name valid for use in ether_open().  Valid prefixes for
X * ethernet interface names are in validname.  Assumes that the device
X * prefixes are unique (i.e. no eckankar0 device exists).
X */
X
Xchar **
Xether_interfaces ()
X{
X    int sfd;
X
X    register int i;
X    register int j;
X    register int k;
X    register int l;
X    int numinter;
X
X    if (checked)
X	return (result);		/* we have alread done this */
X
X    /* we have not yet checked the interfaces */
X
X    if ((sfd = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
X    {
X#ifdef DEBUG
X	perror ("libether socket:");
X#endif
X	return (0);
X    }
X
X    _ether_ifconf.ifc_len = sizeof (cbuf);
X    _ether_ifconf.ifc_buf = cbuf;
X    if (ioctl (sfd, SIOCGIFCONF, (char *) &_ether_ifconf) < 0)
X    {
X#ifdef DEBUG
X	perror ("libether SIOCGIFCONF:");
X#endif
X	(void) close (sfd);
X	return (0);
X    }
X
X    k = 0;
X    numinter = _ether_ifconf.ifc_len / sizeof (struct ifreq);
X    for (i = 0; i < numinter; i++)
X    {
X	for (j = 0; validname[j] != 0; j++)
X	    if (strncmp (_ether_ifconf.ifc_req[i].ifr_name,
X			 validname[j], 2) == 0)
X	    {
X		for (l = 0; l < k; l++)
X		    if (!strcmp (result[l], _ether_ifconf.ifc_req[i].ifr_name))
X		    {
X			if (_ether_ifconf.ifc_req[i].ifr_addr.sa_family
X			    == AF_INET)
X			    _ether_ifindex[l] = i;
X
X			goto duplicate;
X		    }
X
X		(void) strncpy (names + IFNAMSIZ * k,
X				_ether_ifconf.ifc_req[i].ifr_name, IFNAMSIZ);
X		result[k] = names + IFNAMSIZ * k;
X		if (_ether_ifconf.ifc_req[i].ifr_addr.sa_family == AF_INET)
X		    _ether_ifindex[k] = i;
X		else
X		    _ether_ifindex[k] = -1;
X		++k;
X	    }
X      duplicate:
X	;
X    }
X    result[k] = 0;
X
X
X    (void) close (sfd);
X    checked = 1;
X    return (result);
X}
END_OF_FILE
if test 2675 -ne `wc -c <'./src/etherints.c'`; then
    echo shar: \"'./src/etherints.c'\" unpacked with wrong size!
fi
# end of './src/etherints.c'
fi
if test -f './src/etherip2e.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./src/etherip2e.c'\"
else
echo shar: Extracting \"'./src/etherip2e.c'\" \(4804 characters\)
sed "s/^X//" >'./src/etherip2e.c' <<'END_OF_FILE'
X/* $Id: etherip2e.c,v 2.1 89/10/24 17:53:25 dupuy Exp $ */
X
X#include <sys/types.h>			/* in_addr (u_short) */
X#include <sys/ioctl.h>			/* ioctl */
X#include <sys/errno.h>			/* ENXIO */
X#include <sys/time.h>			/* timeval */
X#include <sys/socket.h>			/* sockaddr */
X#ifdef _SOCKET_				/* 4.0 system? */
X#include <sys/sockio.h>			/* SIOCGCONF */
X#include <net/if_arp.h>			/* arpreq */
X#endif
X#include <net/if.h>			/* ifreq */
X#include <netinet/in.h>			/* in_addr */
X
X#ifndef FD_SETSIZE
X#define fd_set int
X#else
X#if defined (ultrix) && defined (lint)
X#define fd_set int
X#endif
X#endif
X
X#ifndef IPPORT_DISCARD
X#define IPPORT_DISCARD 9		/* not worth looking up in services */
X#endif
X
X#include "libether.h"
X
X/*
X * derived from ethertools/iptoea.c
X *
X * Copyright (c) 1988 Philip L. Budne and The Trustees of Boston University
X * All Rights Reserved
X *
X * Permission is granted to any individual or institution to use, copy, or
X * redistribute this software so long as it is not sold for profit, provided
X * that this notice and the original copyright notices are retained.  Boston
X * University makes no representations about the suitability of this software
X * for any purpose.  It is provided "as is" without express or implied
X * warranty.
X */
X
Xextern int errno;
X
Xether_addr *
Xether_ip2e (ipaddr, addr)
Xstruct in_addr *ipaddr;
Xether_addr *addr;
X{
X    int sockfd;
X    char cbuf[MAXNUMIF * sizeof (struct ifreq)];
X    struct sockaddr_in *sin;
X    struct arpreq arp;
X    struct timeval tv;
X    struct ifconf ifc;
X    int allocated = 0;
X    int numinter;
X    int saved_errno;
X    int i;
X
X    if (addr == 0)
X    {
X	addr = (ether_addr *) malloc (sizeof (ether_addr));
X	allocated++;
X    }
X
X    if (addr == 0)
X	return (0);
X
X    if ((sockfd = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
X    {
X	saved_errno = errno;
X#ifdef DEBUG
X	perror ("ether_ip2e: socket");
X#endif
X	goto failed2open;
X    }
X
X    arp.arp_ha.sa_family = AF_UNSPEC;
X    arp.arp_pa.sa_family = AF_INET;
X    sin = (struct sockaddr_in *) &arp.arp_pa;
X    bcopy ((char *) ipaddr, (char *) &sin->sin_addr, sizeof (*ipaddr));
X    sin->sin_port = htons (IPPORT_DISCARD);
X
X    /*
X     * First, check the arp table once.
X     */
X
X    if (!ioctl (sockfd, SIOCGARP, (char *) &arp) && arp.arp_flags & ATF_COM)
X    {
X	bcopy (arp.arp_ha.sa_data, (char *) addr, sizeof (*addr));
X	(void) close (sockfd);
X	return (addr);
X    }
X
X    /*
X     * Then force a kernel ARP resolution by sending a datagram to the IP
X     * host. The MSG_DONTROUTE flag prevents the kernel from using a route to
X     * another IP network (which would not be reachable at the ethernet
X     * level).	We use the discard service to avoid complications.
X     */
X
X    if (sendto (sockfd, (char *) &sockfd, 1, MSG_DONTROUTE,
X		(struct sockaddr *) sin, sizeof (*sin)) < 0)
X    {
X	saved_errno = errno;
X
X#ifdef DEBUG
X	perror ("ether_ip2e: sendto");
X#endif
X	goto failed;
X    }
X
X    /*
X     * Now loop for a short while (.5 - 1.0 sec) looking for the ARP entry.
X     */
X
X    tv.tv_sec = 0;
X    tv.tv_usec = 100000;		/* .1 second */
X
X    for (i = 0; i < 10; i++)
X    {
X	if (ioctl (sockfd, SIOCGARP, (char *) &arp) < 0)
X	{
X	    if (errno != ENXIO)		/* unexpected error */
X	    {
X		saved_errno = errno;
X#ifdef DEBUG
X		perror ("ether_ip2e: ioctl (SIOCGARP)");
X#endif
X		goto failed;
X	    }
X
X	    /*
X	     * Penalize for no entry yet (wait longer if incomplete found).
X	     */
X
X	    i++;
X	}
X	else if (arp.arp_flags & ATF_COM)
X	{
X	    bcopy (arp.arp_ha.sa_data, (char *) addr, sizeof (*addr));
X	    (void) close (sockfd);
X	    return (addr);
X	}
X
X	(void) select (0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &tv);
X    }
X
X    /*
X     * As a last resort, since arp tables don't keep entries for the local
X     * interfaces, we scan the local interfaces to check for a match.
X     */
X
X    ifc.ifc_len = sizeof (cbuf);
X    ifc.ifc_buf = cbuf;
X    if (ioctl (sockfd, SIOCGIFCONF, (char *) &ifc) < 0)
X    {
X#ifdef DEBUG
X	perror ("libether SIOCGIFCONF:");
X#endif
X	goto failed;
X    }
X
X    (void) close (sockfd);
X
X    numinter = ifc.ifc_len / sizeof (struct ifreq);
X    for (i = 0; i < numinter; i++)
X    {
X	struct sockaddr_in *inaddr;
X
X	if (ifc.ifc_req[i].ifr_addr.sa_family == AF_INET)
X	{
X	    inaddr = (struct sockaddr_in *) &ifc.ifc_req[i].ifr_addr;
X	    if (ipaddr->s_addr == inaddr->sin_addr.s_addr)
X	    {
X
X		/*
X		 * The IP address given corresponds to a local interface; get
X		 * the ethernet address for that interface if possible;
X		 */
X
X		if (ether_intfaddr (ifc.ifc_req[i].ifr_name, addr) == 0)
X		{
X		    saved_errno = errno;
X		    goto failed2open;
X		}
X
X		return (addr);		/* got the address - we're done */
X	    }
X	}
X    }
X
X    saved_errno = EHOSTDOWN;
X    goto failed2open;
X
X  failed:
X
X    (void) close (sockfd);
X
X  failed2open:
X
X    if (allocated)
X	free ((char *) addr);
X
X    errno = saved_errno;
X    return (0);
X}
END_OF_FILE
if test 4804 -ne `wc -c <'./src/etherip2e.c'`; then
    echo shar: \"'./src/etherip2e.c'\" unpacked with wrong size!
fi
# end of './src/etherip2e.c'
fi
if test -f './tests/ctp.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./tests/ctp.h'\"
else
echo shar: Extracting \"'./tests/ctp.h'\" \(3080 characters\)
sed "s/^X//" >'./tests/ctp.h' <<'END_OF_FILE'
X/* $Id: ctp.h,v 1.2 89/10/24 17:54:33 dupuy Exp $ */
X
X/*
X * derived from ethertools/ctp.h
X * 
X * Copyright (c) 1988 Philip L. Budne and The Trustees of Boston University All
X * Rights Reserved
X * 
X * Permission is granted to any individual or institution to use, copy, or
X * redistribute this software so long as it is not sold for profit, provided
X * that this notice and the original copyright notices are retained.  Boston
X * University makes no representations about the suitability of this software
X * for any purpose.  It is provided "as is" without express or implied
X * warranty.
X */
X
X/*
X * Make sure we have the fd_set macros
X */
X
X#ifndef FD_SETSIZE
X#define FD_SETSIZE 256			/* Ultrix uses a chintzy 64 */
X#endif
X
X#include <sys/param.h>
X
X#ifndef FD_SET				/* no fd_set macros in sys/types.h */
X
X#if NOFILE > 32				/* assumes we included sys/param.h */
X
X#ifndef NBBY
X#define NBBY	8			/* number of bits in a byte */
X#endif
X
Xtypedef long fd_mask;
X#define NFDBITS (sizeof(fd_mask) * NBBY)/* bits per mask */
X#ifndef howmany
X#define howmany(x, y)	(((x)+((y)-1))/(y))
X#endif
X
X#define fd_set real_fd_set
X
Xtypedef struct real_fd_set
X{
X    fd_mask fds_bits[howmany (FD_SETSIZE, NFDBITS)];
X}           real_fd_set;
X
X#define FD_SET(n, p)	((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
X#define FD_CLR(n, p)	((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
X#define FD_ISSET(n, p)	((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
X#define FD_ZERO(p)	bzero((char *)(p), sizeof(*(p)))
X
X#define param(s)	((int *) (s))
X
X#else					/* NOFILE <= 32 */
X
X/*
X * Create the fd_set type, just in case this isn't 4.2.
X */
X
X#define fd_set real_fd_set
X
Xtypedef struct real_fd_set
X{
X    long fds_bits[1];
X}           real_fd_set;
X
X#define FD_SET(f,s)	((s)->fds_bits[0] |= (1 << (f)))
X#define FD_CLR(f,s)	((s)->fds_bits[0] &= ~(1 << (f)))
X#define FD_ISSET(f,s)	((s)->fds_bits[0] & (1 << (f)))
X#define FD_ZERO(s)	((s)->fds_bits[0] = 0)
X
X#define param(s)	((int *) (s))
X
X#endif					/* NOFILE > 32 */
X
X#else
X
X#define param(s)	((fd_set *) (s))
X
X#endif					/* FD_SET */
X
X/*
X * CTP Protocol constants
X */
X
X#define CTPTYPE 0x9000
X
X#define CTP_REP 1			/* in VAX byte order */
X#define CTP_FWD 2
X
X/*
X * CTP packet structures
X */
X
X#include <sys/time.h>
X#include "ether.h"
X
Xtypedef struct ctppacket		/* CTP packet layout */
X{
X    int :0;				/* force long alignment for timeval */
X    unsigned short skip;		/* CTP skip in VAX byte order */
X
X    char data[ETHER_MAX - sizeof (unsigned short)];
X}
X          ctp_packet;
X
Xtypedef struct ctpforward		/* forward subpacket */
X{
X    unsigned short function;		/* CTP_FWD */
X    ether_addr addr;
X}
X           ctp_forward;
X
Xtypedef struct ctpreply			/* reply subpacket */
X{
X    unsigned short function;		/* CTP_REP */
X
X    /* The following is data that we use for own purposes */
X
X    unsigned short pid;			/* pid of sender -- not swapped */
X    unsigned short seq;			/* sequence number -- not swapped */
X
X    short sendt[4];			/* really struct timeval */
X}
X         ctp_reply;
X
X#define MAXPATH ((ETHER_MAX - sizeof (ctp_reply) - 2)  / sizeof (ctp_forward))
END_OF_FILE
if test 3080 -ne `wc -c <'./tests/ctp.h'`; then
    echo shar: \"'./tests/ctp.h'\" unpacked with wrong size!
fi
# end of './tests/ctp.h'
fi
echo shar: End of archive 2 \(of 3\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 3 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.