[net.sources] 4.2 arp enhancements

shannon@sun.uucp (Bill Shannon) (03/20/84)

----- cut here and extract with sh
echo x - README
sed 's/^X//' >README <<'!Funky!Stuff!'

	NEW ARP HANDLING FOR 4.2bsd  (Release of 03/16/84)

The code included here can be inserted into a VAX 4.2bsd system (with a
little work) to greatly improve the flexibility and usability of the
Ethernet Address Resolution Protocol.  (See enclosed manual pages for
more information.)

There is no warranty of merchantability nor any warranty of fitness for
a particular purpose nor any other warranty, either express or implied,
as to the accuracy of the enclosed materials or as to their suitability
for any particular purpose.  Accordingly, Sun Microsystems Inc. assumes
no responsibility for their use by the recipient.  Further, Sun Microsystems
Inc. assumes no obligation to furnish any assistance of any kind whatsoever,
or to furnish any additional information or documentation.

The included files are:

	README			- this file
	arp.4p			- improved ARP manual page
	arp.8c			- manual page for new arp command
	ifconfig.8c		- replacement manual page describing new options
	arp.c			- code for new arp command
	if.c.diffs		- changes to /sys/net/if.c
	if.h.diffs		- changes to /sys/net/if.h
	if_ec.c.diffs		- changes to /sys/vaxif/if_ec.c, as an example
				  of changes necessary to ALL network drivers
	if_ether.c.diffs	- changes to /sys/netinet/if_ether.c
	if_ether.h.diffs	- changes to /sys/netinet/if_ether.h
	ifconfig.c.diffs	- changes to /usr/src/etc/if_config.c
	ioctl.h.diffs		- changes to /sys/h/ioctl.h (and /usr/include/
				  sys/ioctl.h if it isn't a link)
	ether_print		- small routine to be added somewhere, it's in
				  autoconf.c in the Sun system, but if_ether.c
				  may be more appropriate in the VAX system

Overview of changes

	You will have to change all of your network device drivers in order
to put this code into your system.  The changes should be straight-forward
and are necessitated by the following changes to common code.

	1.  Ethernet addresses are now a structure instead of a 6 byte
	    array.  This allows them to be assigned directly instead of
	    having to use bcopy.  Hint - look for "edst" in the driver,
	    all references to it will have to be changed.

	2.  The third address to the driver ioctl routines has changed.
	    See the enclosed modifications of if_ec.c for an example.

	3.  Routine arpmyaddr() is gone.  It always returned zero.
	    Most drivers call it in the attach routine, just remove
	    the line containing the call.

	The *.diffs files are diff -e scripts that can be applied to the
standard files supplied with 4.2bsd.  The diffs apply to the following
versions of these files:

	/*	if.c	6.2	83/09/27	*/
	/*	if.h	6.2	83/08/28	*/
	/*	if_ec.c	6.1	83/07/29	*/
	/*	if_ether.c	6.2	83/08/28	*/
	/*	if_ether.h	6.2	83/09/26	*/
	/*	ioctl.h	6.1	83/07/29	*/
	static char sccsid[] = "@(#)ifconfig.c	4.5 (Berkeley) 11/2/83";

If you've modified any of these files locally you'll have to find the
originals from your 4.2 distribution and apply the diffs to them, then
merge in any local changes.  Apply the diffs using a set of commands
like this:

	chmod +w file
	ed - file <file.diffs

You may want to save the originals before changing them.

	Good luck!

					Bill Shannon
					{ucbvax, decvax}!sun!shannon
					Sun Microsystems, Inc.
!Funky!Stuff!
echo x - arp.4p
sed 's/^X//' >arp.4p <<'!Funky!Stuff!'
X.\" @(#)arp.4p 1.8 84/02/02 SMI; from UCB 4.1
X.TH ARP 4P "11 January 1984"
X.SH NAME
arp \- Address Resolution Protocol
X.SH SYNOPSIS
X.B "pseudo-device ether"
X.SH DESCRIPTION
ARP is a protocol used to dynamically map between DARPA Internet
and 10Mb/s Ethernet addresses.  It is
used by all the 10Mb/s Ethernet interface drivers.
X.PP
ARP caches Internet-Ethernet address mappings.  When an interface
requests a mapping for an address not in the cache, ARP queues the
message which requires the mapping and broadcasts
a message on the associated network requesting the address mapping.
If a response is provided, the new mapping is cached and any pending
messages are transmitted.
ARP will queue
at most one packet while waiting for a mapping request to be responded to;
only the most recently ``transmitted'' packet is kept.
X.PP
To enable communications with systems which do not use ARP, ioctls
are provided to enter and delete entries in the Internet-to-Ethernet tables.
Usage:
X.LP
X.nf
X.ft B
	#include <sys/ioctl.h>
	#include <sys/socket.h>
	#include <net/if.h>
	struct arpreq arpreq;

	ioctl(s, SIOCSARP, (caddr_t)&arpreq);
	ioctl(s, SIOCGARP, (caddr_t)&arpreq);
	ioctl(s, SIOCDARP, (caddr_t)&arpreq);
X.fi
X.ft R
Each ioctl takes the same structure as an argument.
SIOCSARP sets an ARP entry, SIOCGARP gets an ARP entry, and SIOCDARP
deletes an ARP entry.  These ioctls may be applied to any socket descriptor
X.I s,
but only by the super-user.
The
X.I arpreq
structure contains:
X.LP
X.nf
	/*
	 * ARP ioctl request
	 */
	struct arpreq {
		struct sockaddr	arp_pa;		/* protocol address */
		struct sockaddr	arp_ha;		/* hardware address */
		int	arp_flags;		/* flags */
	};
	/*  arp_flags field values */
	#define ATF_COM		2	/* completed entry (arp_ha valid) */
	#define	ATF_PERM	4	/* permanent entry */
	#define	ATF_PUBL	8	/* publish (respond for other host) */
X.fi
X.LP
The address family for the
X.I arp_pa
sockaddr must be AF_INET; for the 
X.I arp_ha
sockaddr it must be AF_UNSPEC.
The only flag bits which may be written are ATF_PERM and ATF_PUBL.
ATF_PERM causes the entry to be permanent if the ioctl call succeeds.
The peculiar nature of the ARP tables may cause the ioctl to fail if more
than 4 (permanent) Internet host addresses hash to the same slot.
ATF_PUBL specifies that the ARP code should respond to ARP requests for the
indicated host coming from other machines.  This allows a Sun to act as an
"ARP server" which may be useful in convincing an ARP-only machine to talk
to a non-ARP machine.
X.PP
ARP watches passively for hosts impersonating the local host (i.e. a host
which responds to an ARP mapping request for the local host's address).
X.SH DIAGNOSTICS
X.B "duplicate IP address!! sent from ethernet address: %x:%x:%x:%x:%x:%x."
ARP has discovered another host on the local network which responds to
mapping requests for its own Internet address.
X.SH SEE ALSO
ec(4S), ie(4S), inet(4F), arp(8C), ifconfig(8C)
X.br
An Ethernet Address Resolution Protocol, RFC826, Dave Plummer, MIT (Sun 800-1059-01)
X.SH BUGS
ARP packets on the Ethernet use only 42 bytes of data, however, the smallest
legal Ethernet packet is 60 bytes (not including CRC).
Some systems may not enforce the minimum packet size, others will.
!Funky!Stuff!
echo x - arp.8c
sed 's/^X//' >arp.8c <<'!Funky!Stuff!'
X.\" @(#)arp.8c 1.1 84/01/12 SMI;
X.TH ARP 8C "12 January 1984"
X.SH NAME
arp \- address resolution display and control
X.SH SYNOPSIS
X.B arp
X.I hostname
X.br
X.B arp -a
[
X.I vmunix
] [
X.I kmem
]
X.br
X.B arp -d
X.I hostname
X.br
X.B arp -s
X.I hostname ether_addr
[
X.B temp
] [
X.B pub
]
X.br
X.B arp -f
X.I filename
X.SH DESCRIPTION
The
X.I arp
program displays and modifies the Internet-to-Ethernet address translation
tables used by the address resolution protocol (
X.IR arp (4p)).
X.LP
With no flags, the program displays the current ARP entry for
X.I hostname.
With the
X.B -a
flag, the program displays all of the current ARP entries by reading the table
from the file
X.I kmem
(default /dev/kmem) based on the kernel file 
X.I vmunix 
(default /vmunix).
X.LP
With the
X.B -d
flag, a super-user may delete an entry for the host called
X.I hostname.
X.LP
The
X.B -s
flag is given to create an ARP entry for the host called
X.I hostname
with the Ethernet address 
X.I ether_addr.
The Ethernet address is given as six hex bytes separated by colons.
The entry will be permanent unless the word
X.B temp
is given in the command. 
If the word
X.B pub
is given, the entry will be "published", e.g., this system will
respond to ARP requests for 
X.I hostname
even though the hostname is not its own.
X.LP
The 
X.B -f
flag causes the file
X.I filename
to be read and multiple entries to be set in the ARP tables.  Entries
in the file should be of the form
X.IP
X.I hostname ether_addr
[
X.B temp
] [
X.B pub
]
X.LP
with argument meanings as given above.
X.SH "SEE ALSO"
arp(4p), ifconfig(8c)
!Funky!Stuff!
echo x - arp.c
sed 's/^X//' >arp.c <<'!Funky!Stuff!'
#ifndef lint
static	char sccsid[] = "@(#)arp.c 1.1 83/11/29 SMI";
#endif

/*
 * arp - display, set, and delete arp table entries
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <netdb.h>
#include <nlist.h>
#include <net/if.h>
#include <netinet/if_ether.h>

extern int errno;

main(argc, argv)
	char **argv;
{
	if (argc >= 2 && strcmp(argv[1], "-a") == 0) {
		char *kernel = "/vmunix", *mem = "/dev/kmem";

		if (argc >= 3)
			kernel = argv[2];
		if (argc >= 4)
			mem = argv[3];
		dump(kernel, mem);
		exit(0);
	}
	if (argc == 2) {
		get(argv[1]);
		exit(0);
	}
	if (argc >= 4 && strcmp(argv[1], "-s") == 0) {
		set(argc-2, &argv[2]);
		exit(0);
	}
	if (argc == 3 && strcmp(argv[1], "-d") == 0) {
		delete(argv[2]);
		exit(0);
	}
	if (argc == 3 && strcmp(argv[1], "-f") == 0) {
		file(argv[2]);
		exit(0);
	}
	usage();
	exit(1);
}

/*
 * Process a file to set standard arp entries
 */
file(name)
	char *name;
{
	FILE *fp;
	int i;
	char line[100], arg[4][50], *args[4];

	if ((fp = fopen(name, "r")) == NULL) {
		fprintf(stderr, "arp: cannot open %s\n", name);
		exit(1);
	}
	args[0] = &arg[0][0];
	args[1] = &arg[1][0];
	args[2] = &arg[2][0];
	args[3] = &arg[3][0];
	while(fgets(line, 100, fp) != NULL) {
		i = sscanf(line, "%s %s %s %s", arg[0], arg[1], arg[2], arg[3]);
		if (i < 2) {
			fprintf(stderr, "arp: bad line: %s\n", line);
			continue;
		}
		set(i, args);
	}
	fclose(fp);
}

/*
 * Set an individual arp entry 
 */
set(argc, argv)
	char **argv;
{
	struct arpreq ar;
	struct hostent *hp;
	struct sockaddr_in *sin;
	struct ether_addr *ea;
	int s;
	char *host = argv[0], *eaddr = argv[1];

	argc -= 2;
	argv += 2;
	hp = gethostbyname(host);
	if (hp == NULL) {
		fprintf(stderr, "arp: %s: unknown host\n", host);
		return (1);
	}
	bzero((caddr_t)&ar, sizeof ar);
	ar.arp_pa.sa_family = AF_INET;
	sin = (struct sockaddr_in *)&ar.arp_pa;
	sin->sin_addr = *(struct in_addr *)hp->h_addr;
	ea = (struct ether_addr *)ar.arp_ha.sa_data;
	if (ether_aton(eaddr, ea))
		return;
	ar.arp_flags = ATF_PERM;
	while(argc-- > 0) {
		if (strncmp(argv[0], "temp", 4) == 0)
			ar.arp_flags &= ~ATF_PERM;
		if (strncmp(argv[0], "pub", 3) == 0)
			ar.arp_flags |= ATF_PUBL;
		argv++;
	}
	
	s = socket(AF_INET, SOCK_DGRAM, 0);
	if (s < 0) {
                perror("arp: socket");
                exit(1);
        }
	if (ioctl(s, SIOCSARP, (caddr_t)&ar) < 0) {
		perror(host);
		exit(1);
	}
	close(s);
}


/*
 * Display an individual arp entry
 */
get(host)
	char *host;
{
	struct arpreq ar;
	struct hostent *hp;
	struct sockaddr_in *sin;
	struct ether_addr *ea;
	int s;

	hp = gethostbyname(host);
	if (hp == NULL) {
		fprintf(stderr, "arp: %s: unknown host\n", host);
		exit(1);
	}
	bzero((caddr_t)&ar, sizeof ar);
	ar.arp_pa.sa_family = AF_INET;
	sin = (struct sockaddr_in *)&ar.arp_pa;
	sin->sin_addr = *(struct in_addr *)hp->h_addr;
	s = socket(AF_INET, SOCK_DGRAM, 0);
	if (s < 0) {
                perror("arp: socket");
                exit(1);
        }
	if (ioctl(s, SIOCGARP, (caddr_t)&ar) < 0) {
		if (errno == ENXIO)
			printf("%s (%s) -- no entry\n",
			    host, inet_ntoa(sin->sin_addr));
		else
			perror("SIOCGARP");
		exit(1);
	}
	close(s);
	ea = (struct ether_addr *)ar.arp_ha.sa_data;
	printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr));
	if (ar.arp_flags & ATF_COM)
		ether_print(ea);
	else
		printf("(incomplete)");
	if (!(ar.arp_flags & ATF_PERM)) printf(" temporary");
	if (ar.arp_flags & ATF_PUBL) printf(" published");
	printf("\n");
}

/*
 * Delete an arp entry 
 */
delete(host)
	char *host;
{
	struct arpreq ar;
	struct hostent *hp;
	struct sockaddr_in *sin;
	int s;

	hp = gethostbyname(host);
	if (hp == NULL) {
		fprintf(stderr, "arp: %s: unknown host\n", host);
		exit(1);
	}
	bzero((caddr_t)&ar, sizeof ar);
	ar.arp_pa.sa_family = AF_INET;
	sin = (struct sockaddr_in *)&ar.arp_pa;
	sin->sin_addr = *(struct in_addr *)hp->h_addr;
	s = socket(AF_INET, SOCK_DGRAM, 0);
	if (s < 0) {
                perror("arp: socket");
                exit(1);
        }
	if (ioctl(s, SIOCDARP, (caddr_t)&ar) < 0) {
		if (errno == ENXIO)
			printf("%s (%s) -- no entry\n",
			    host, inet_ntoa(sin->sin_addr));
		else
			perror("SIOCDARP");
		exit(1);
	}
	close(s);
	printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr));
}

struct nlist nl[] = {
#define	X_ARPTAB	0
	{ "_arptab" },
#define	X_ARPTAB_SIZE	1
	{ "_arptab_size" },
	{ "" },
};

/*
 * Dump the entire arp table
 */
dump(kernel, mem)
	char *kernel, *mem;
{
	int mf, arptab_size, sz;
	struct arptab *at;
	struct hostent *hp;
	char *host;

	nlist(kernel, nl);
	if(nl[X_ARPTAB_SIZE].n_type == 0) {
		fprintf(stderr, "arp: %s: bad namelist\n", kernel);
		exit(1);
	}
	mf = open(mem, 0);
	if(mf < 0) {
		fprintf(fprintf, "arp: cannot open %s\n", mem);
		exit(1);
	}
	lseek(mf, (long)nl[X_ARPTAB_SIZE].n_value, 0);
	read(mf, &arptab_size, sizeof arptab_size);
	if (arptab_size <=0 || arptab_size > 1000) {
		fprintf(stderr, "arp: %s: namelist wrong\n", kernel);
		exit(1);
	}
	sz = arptab_size * sizeof (struct arptab);
	at = (struct arptab *)malloc(sz);
	if (at == NULL) {
		fprintf(stderr, "arp: can't get memory for arptab\n");
		exit(1);
	}
	lseek(mf, (long)nl[X_ARPTAB].n_value, 0);
	if (read(mf, (char *)at, sz) != sz) {
		perror("arp: error reading arptab");
		exit(1);
	}
	close(mf);
	for (; arptab_size-- > 0; at++) {
		if (at->at_iaddr.s_addr == 0 || at->at_flags == 0)
			continue;
		hp = gethostbyaddr((caddr_t)&at->at_iaddr, sizeof at->at_iaddr,
			AF_INET);
		if (hp)
			host = hp->h_name;
		else
			host = "?";
		printf("%s (%s) at ", host, inet_ntoa(at->at_iaddr));
		if (at->at_flags & ATF_COM)
			ether_print(&at->at_enaddr);
		else
			printf("(incomplete)");
		if (!(at->at_flags & ATF_PERM)) printf(" temporary");
		if (at->at_flags & ATF_PUBL) printf(" published");
		printf("\n");
	}
}

ether_print(ea)
	struct ether_addr *ea;
{
	u_char *cp = &ea->ether_addr_octet[0];

	printf("%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
}

ether_aton(a, n)
	char *a;
	struct ether_addr *n;
{
	int i, o[6];

	i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
					   &o[3], &o[4], &o[5]);
	if (i != 6) {
		fprintf(stderr, "arp: invalid Ethernet address '%s'\n", a);
		return (1);
	}
	for (i=0; i<6; i++)
		n->ether_addr_octet[i] = o[i];
	return (0);
}

usage()
{
	printf("Usage: arp hostname\n");
	printf("       arp -a [/vmunix] [/dev/kmem]\n");
	printf("       arp -d hostname\n");
	printf("       arp -s hostname ether_addr [temp] [pub]\n");
	printf("       arp -f filename\n");
}
!Funky!Stuff!
echo x - ether_print
sed 's/^X//' >ether_print <<'!Funky!Stuff!'
ether_print(ea)
	struct ether_addr *ea;
{
	u_char *cp = &ea->ether_addr_octet[0];

	printf("%x:%x:%x:%x:%x:%x\n", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
}
!Funky!Stuff!
echo x - if.c.diffs
sed 's/^X//' >if.c.diffs <<'!Funky!Stuff!'
260a
}

/*
 * Set a new interface address.
 * Called by ND address assignment as well as above
 * XXX Most of what the drivers do is device independent!
 */
if_setaddr(ifp, sa)
	register struct ifnet *ifp;
	struct sockaddr *sa;
{
	if (ifp->if_ioctl == 0)
		return (EOPNOTSUPP);
	return ((*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)sa));
X.
258c
		return ((*ifp->if_ioctl)(ifp, cmd, ifr->ifr_data));
X.
254a
	case SIOCSIFADDR:
		return (if_setaddr(ifp, &ifr->ifr_addr));

X.
218a
	case SIOCSARP:
	case SIOCDARP:
		if (!suser())
			return (u.u_error);
		/* fall through */
	case SIOCGARP:
		return (arpioctl(cmd, data));

X.
194c
	unit = *cp - '0';
X.
192c
	if (*cp == '\0' || cp == name + IFNAMSIZ || cp == name)
X.
1c
/*	@(#)if.c 1.5 83/12/07 SMI; from UCB 6.2 83/09/27	*/
X.
w
!Funky!Stuff!
echo x - if.h.diffs
sed 's/^X//' >if.h.diffs <<'!Funky!Stuff!'
154a

/*
 * ARP ioctl request
 */
struct arpreq {
	struct sockaddr	arp_pa;		/* protocol address */
	struct sockaddr	arp_ha;		/* hardware address */
	int	arp_flags;		/* flags */
};
/*  arp_flags and at_flags field values */
#define	ATF_INUSE	1	/* entry in use */
#define ATF_COM		2	/* completed entry (enaddr valid) */
#define	ATF_PERM	4	/* permanent entry */
#define	ATF_PUBL	8	/* publish entry (respond for other host) */
X.
1c
/*	@(#)if.h 1.6 84/01/11 SMI; from UCB 6.2 83/08/28	*/
X.
w
!Funky!Stuff!
echo x - if_ec.c.diffs
sed 's/^X//' >if_ec.c.diffs <<'!Funky!Stuff!'
754c
		ecsetaddr(ifp, sin);
X.
751a
		sa = (struct sockaddr *)data;
		if (sa->sa_family == AF_UNSPEC) {
			if (sa->sa_data[0] & 1)	/* broad or multi-cast */
				return (EINVAL);
			es->es_addr = *(struct ether_addr *)sa->sa_data;
			ecinit(ifp->if_unit);
			break;
		}
		sin = (struct sockaddr_in *)data;
		if (sin->sin_family != AF_INET)
			return (EINVAL);
X.
746c
	struct ec_softc *es = &ec_softc[ifp->if_unit];
	struct sockaddr *sa;
	struct sockaddr_in *sin;
X.
584d
582c
	ec->ether_dhost = edst;
	ec->ether_shost = es->es_addr;
X.
539c
		edst = ec->ether_dhost;
X.
516c
		if (!arpresolve(&es->es_ac, m, &idst, &edst))
X.
503c
	struct ether_addr edst;
X.
245d
183d
171c
	cp = (u_char *)&es->es_addr;
X.
1c
/*	if_ec.c	6.1.1	84/03/16	*/
X.
w
!Funky!Stuff!
echo x - if_ether.c.diffs
sed 's/^X//' >if_ether.c.diffs <<'!Funky!Stuff!'
390a
}

arpioctl(cmd, data)
	int cmd;
	caddr_t data;
{
	register struct arpreq *ar = (struct arpreq *)data;
	register struct arptab *at;
	register struct sockaddr_in *sin;
	int s;

	if (ar->arp_pa.sa_family != AF_INET ||
	    ar->arp_ha.sa_family != AF_UNSPEC)
		return (EAFNOSUPPORT);
	sin = (struct sockaddr_in *)&ar->arp_pa;
	s = splimp();
	ARPTAB_LOOK(at, sin->sin_addr.s_addr);
	if (at == NULL) {		/* not found */
		if (cmd != SIOCSARP) {
			splx(s);
			return (ENXIO);
		}
		if (if_ifwithnet(&ar->arp_pa) == NULL) {
			splx(s);
			return (ENETUNREACH);
		}
		at = arptnew(&sin->sin_addr);
	}
	switch (cmd) {

	case SIOCSARP:		/* set entry */
		at->at_enaddr = *(struct ether_addr *)ar->arp_ha.sa_data;
		at->at_flags = ATF_COM | ATF_INUSE |
			(ar->arp_flags & (ATF_PERM|ATF_PUBL));
		at->at_timer = 0;
		if (ar->arp_flags & ATF_PERM) {
			/* never make all entries in a bucket permanent */
			register struct arptab *tat;
			struct in_addr addr;
			
			/* defeat has and try to re-allocate */
			addr = at->at_iaddr;
			at->at_iaddr.s_addr = 0;
			tat = arptnew(&addr);
			if (tat == NULL) {
				arptfree(at);
				splx(s);
				return (EADDRNOTAVAIL);
			}
			arptfree(tat);
			at->at_iaddr = addr;
		}
		break;

	case SIOCDARP:		/* delete entry */
		arptfree(at);
		break;

	case SIOCGARP:		/* get entry */
		*(struct ether_addr *)ar->arp_ha.sa_data = at->at_enaddr;
		ar->arp_flags = at->at_flags;
		break;
	}
	splx(s);
	return (0);
X.
384a
	if (ato == NULL)
		return (NULL);
X.
380c
		if (at->at_flags & ATF_PERM)
			continue;
		if (ato == NULL || at->at_timer > oldest) {
X.
376c
	if (first) {
		first = 0;
		timeout(arptimer, (caddr_t)0, hz);
	}
	at = &arptab[ARPTAB_HASH(addr->s_addr) * ARPTAB_BSIZ];
	ato = NULL;
X.
374a
	static int first = 1;
X.
366a
 * This always succeeds for dynamic entries since arpioctl
 * gaurantees that no bucket can be completely filled
 * with permanent entries.
X.
348a
 * Called just before buffer passed to ipintr.  If ip_src.s_net is 0,
 * then make the ether source address available by saving the mapping.
 */
arpipin(ec, m)
	register struct ether_header *ec;
	register struct mbuf *m;
{
	register struct ip *ip;
	int hlen;
	extern int ipcksum;

	if (m->m_len < sizeof(struct ip))
		return;
	ip = mtod(m, struct ip *);
	if (ip->ip_src.s_net != 0)
		return;
	arpseten(&ip->ip_src, &ec->ether_shost);
}

/*
 * Get an ethernet address, given the IP address.
 */
struct ether_addr *
arpgeten(addr)
	register struct in_addr *addr;
{
	register struct arptab *at;

	ARPTAB_LOOK(at, addr->s_addr);
	if (at == 0 || (at->at_flags & ATF_COM) == 0)
		return (0);
	return (&at->at_enaddr);
}

/*
 * Set an ether/IP mapping.  Called externally to force a mapping.
 */
arpseten(iaddr, eaddr)
	struct in_addr *iaddr;
	struct ether_addr *eaddr;
{
	register struct arptab *at;
	int s = splimp();

	ARPTAB_LOOK(at, iaddr->s_addr);
	if (at == 0)
		at = arptnew(iaddr);
	at->at_timer = ARPT_KILLC - 3;	/* so it expires faster than normal */
	at->at_flags |= ATF_COM;
	if (at->at_hold)
		m_freem(at->at_hold);
	at->at_hold = 0;
	at->at_enaddr = *eaddr;
	splx(s);
}
#endif IPENADDR
	
/*
X.
347a
#ifdef IPENADDR
X.
337,338c
	eh->ether_dhost = arp_tha(ea);
X.
327,334c
	arp_tha(ea) = arp_sha(ea);
	arp_tpa(ea) = arp_spa(ea);
	arp_sha(ea) = at->at_enaddr;
	arp_spa(ea) = itaddr;
X.
325a
	ARPTAB_LOOK(at, itaddr.s_addr);
	if (at == NULL) {
		if (itaddr.s_addr != myaddr.s_addr)
			goto out;	/* if I am not the target */
		at = arptnew(&myaddr);
		at->at_enaddr = ac->ac_enaddr;
		at->at_flags |= ATF_COM;
	} 
	if (itaddr.s_addr != myaddr.s_addr && (at->at_flags & ATF_PUBL) == 0)
		goto out;
		
X.
320,321c
		at->at_enaddr = arp_sha(ea);
X.
315,318c
	} else if (itaddr.s_addr == myaddr.s_addr) {
		/* ensure we have a table entry */
X.
303,305c
	if (at) {		/* XXX ? - can overwrite ATF_PERM */
		at->at_enaddr = arp_sha(ea);
X.
295,297c
		ether_print(&arp_sha(ea));
		itaddr = myaddr;
X.
288,290c
	isaddr = arp_spa(ea);
	itaddr = arp_tpa(ea);
	if (!bcmp((caddr_t)&arp_sha(ea), (caddr_t)&ac->ac_enaddr,
X.
283a
	if (ac->ac_if.if_flags & IFF_NOARP)
		goto out;
X.
266c
 * is received.  Algorithm is that given in RFC 826.
X.
243,264d
225c
		*desten = at->at_enaddr;
X.
217,221c
		if (ifp->if_flags & IFF_NOARP) {
			*desten = ac->ac_enaddr;
			desten->ether_addr_octet[3] = (lna >> 16) & 0x7f;
			desten->ether_addr_octet[4] = (lna >> 8) & 0xff;
			desten->ether_addr_octet[5] = lna & 0xff;
			splx(s);
			return (1);
		} else {
			at = arptnew(destip);
			at->at_hold = m;
			arpwhohas(ac, destip);
			splx(s);
			return (0);
		}
X.
213a
#endif IPENADDR
X.
207,211c
#ifdef IPENADDR
	if (destip->s_net == 0) {	/* real IP address unknown */
		struct ether_addr *arpgeten(), *ap;
		if ((ap = arpgeten(destip)) == NULL)
			return (0);
		*desten = *ap;
X.
195,196c
		*desten = etherbroadcastaddr;
X.
189a
	register int i;
X.
186c
	register struct ether_addr *desten;
X.
168c
	return ((*ac->ac_if.if_output)(&ac->ac_if, m, &sa));
X.
162,166c
	arp_sha(ea) = ac->ac_enaddr;
	arp_spa(ea) = ((struct sockaddr_in *)&ac->ac_if.if_addr)->sin_addr;
	arp_tpa(ea) = *addr;
X.
159,160c
	ea->arp_hln = sizeof arp_sha(ea);	/* hardware address length */
	ea->arp_pln = sizeof arp_spa(ea);	/* protocol address length */
X.
154,155c
	eh->ether_dhost = etherbroadcastaddr;
X.
148,149c
		return (1);
	m->m_len = sizeof *ea;
X.
124c
			if (at->at_flags == 0 || (at->at_flags & ATF_PERM))
X.
105,119d
100a
	register struct arpcom *ac;
X.
78,96d
62,75c
#define	IPENADDR 0		/* enable passing enaddr's thru IP layer */
X.
59c
struct ether_addr etherbroadcastaddr = {{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }};
X.
51d
37a
int	arptab_size = ARPTAB_SIZE;	/* for arp command */
X.
19,33d
16a
#include "../netinet/in_systm.h"
#include "../netinet/ip.h"
X.
13a
#include "../h/ioctl.h"
X.
1c
#ifndef lint
static	char sccsid[] = "@(#)if_ether.c 1.7 84/02/08 SMI";
#endif
X.
w
!Funky!Stuff!
echo x - if_ether.h.diffs
sed 's/^X//' >if_ether.h.diffs <<'!Funky!Stuff!'
61,62c
struct ether_addr etherbroadcastaddr;
X.
59a
/*
 * Internet to ethernet address resolution table.
 */
struct	arptab {
	struct	in_addr at_iaddr;	/* internet address */
	struct	ether_addr at_enaddr;	/* ethernet address */
	struct	mbuf *at_hold;		/* last packet until resolved/timeout */
	u_char	at_timer;		/* minutes since last reference */
	u_char	at_flags;		/* flags */
};

X.
56c
	struct ether_addr ac_enaddr;	/* ethernet hardware address */
X.
47a
#define	arp_sha(ea)	(*(struct ether_addr *)(ea)->arp_xsha)
#define	arp_spa(ea)	(*(struct in_addr *)(ea)->arp_xspa)
#define	arp_tha(ea)	(*(struct ether_addr *)(ea)->arp_xtha)
#define	arp_tpa(ea)	(*(struct in_addr *)(ea)->arp_xtpa)
X.
43,46c
	u_char	arp_xsha[6];	/* sender hardware address */
	u_char	arp_xspa[4];	/* sender protocol address */
	u_char	arp_xtha[6];	/* target hardware address */
	u_char	arp_xtpa[4];	/* target protocol address */
X.
7,8c
	struct	ether_addr ether_dhost;
	struct	ether_addr ether_shost;
X.
3a
 * Ethernet address - 6 octets
 */
struct ether_addr {
	u_char	ether_addr_octet[6];
};

/*
X.
1c
/*	@(#)if_ether.h 1.4 84/01/11 SMI; from UCB 4.5 83/05/15	*/
X.
w
!Funky!Stuff!
echo x - ifconfig.8c
sed 's/^X//' >ifconfig.8c <<'!Funky!Stuff!'
X.\" @(#)ifconfig.8c 1.2 84/01/11 SMI;
X.TH IFCONFIG 8C "12 January 1984"
X.UC 4
X.SH NAME
ifconfig \- configure network interface parameters
X.SH SYOPNSIS
X.B /etc/ifconfig
interface
[
X.I Ethernet_address
] [
X.I hostname
] [
X.I parameters
]
X.SH DESCRIPTION
X.I Ifconfig
is used to assign an address
to a network interface and/or to configure
network interface parameters.
X.I Ifconfig
must be used at boot time to define the network address
of each interface present on a machine; it may also be used at
a later time to redefine an interface's address.
Used without options,
X.I ifconfig
displays the current configuration for a network interface.
Only the super-user may modify the configuration of a network interface.
X.LP
The
X.B interface
parameter is a string of the form ``name unit'', for example ``ie0''.
X.SH OPTIONS
X.LP
\fIEthernet_address\fP is the hardware Ethernet address of a given
machine.  The address is a 6-byte hexadecimal value; each byte of the
address is separated by a colon.  A typical Ethernet adddress is
`8:0:20:1:1:A3'.  This address is contained in the ID PROM on the Sun-2 CPU
Board, and is reported at boot time as one of the PROM monitor's sign-on
messages.  The \fIEthernet_address\fP option is normally not used \(em
the hardware supplies the default; the option is used only when trying
to talk to a device which does not support ARP (like a VAX on a 4.1c
network).
X.LP
\fIhostname\fP may be either the hostname of a given machine (present in
the hostname database, \fIhosts\fP\^(5)), or the complete Internet
address consisting of your system's network number and the machine's
unique host number.  A typical Internet address might be ``192.9.200.44'',
where ``192.9.200'' is the network number and ``44'' is the machine's
hostnumber.
To find a machine's Internet address, consult the local \fI/etc/hosts\fP file.
X.PP
The following \fIparameters\fP may be set with 
X.IR ifconfig :
X.TP 15
X.B "\ \ \ up"
Mark an interface ``up''. 
X.TP 15
X.B "\ \ \ down"
Mark an interface ``down''.  When an interface is
marked ``down'', the system will not attempt to
transmit messages through that interface. 
X.TP 15
X.B "\ \ \ trailers"
Enable the use of a ``trailer'' link level encapsulation when
sending (default).
If a network interface supports
X.IR trailers ,
the system will, when possible, encapsulate outgoing
messages in a manner which minimizes the number of
memory to memory copy operations performed by the receiver.
X.TP 15
X.B "\ \ \ \-trailers"
Disable the use of a ``trailer'' link level encapsulation.
X.TP 15
X.B "\ \ \ arp
Enable the use of the Address Resolution Protocol in mapping
between network level addresses and link level addresses (default). 
This is currently implemented for mapping between DARPA Internet
addreses and 10Mb/s Ethernet addresses.
X.TP 15
X.B "\ \ \ \-arp"
Disable the use of the Address Resolution Protocol.
X.RE
X.SH DIAGNOSTICS
Messages indicating the specified interface does not exit, the
requested address is unknown, the user is not privileged and
tried to alter an interface's configuration.
X.SH "SEE ALSO"
rc(8), intro(4N), netstat(1)
!Funky!Stuff!
echo x - ifconfig.c.diffs
sed 's/^X//' >ifconfig.c.diffs <<'!Funky!Stuff!'
187c
	n = sscanf(s, "%x:%x:%x:%x:%x:%x:%x:%x",
		&o[0], &o[1], &o[2], &o[3],
		&o[4], &o[5], &o[6], &o[7]);
	if (n > 0) {
		p = sa->sa_data;
		ip = &o[0];
		while (n--)
			*p++ = *ip++;
		sa->sa_family = AF_UNSPEC;
		return;
	}
	fprintf(stderr, "ifconfig: %s: bad address\n", s);
X.
163a
	bzero((caddr_t)sa, sizeof *sa);
X.
162c
	int val, n, o[8], *ip;
	char *p;
X.
159a
	struct sockaddr_in *sin = (struct sockaddr_in *)sa;
X.
158c
	struct sockaddr *sa;
X.
156c
getaddr(s, sa)
X.
128c
	printb("flags", ifr.ifr_flags, IFFBITS); putchar('\n');
X.
125a
	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
		Perror("ioctl (SIOCGIFFLAGS)");
		exit(1);
	}
X.
110,111c
		ifr.ifr_flags |= value;
X.
108c
		ifr.ifr_flags &= ~value;
X.
105a
	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
		Perror("ioctl (SIOCGIFFLAGS)");
		exit(1);
	}
X.
95c
	getaddr(addr, &ifr.ifr_addr);
X.
65,70d
36,37d
20d
2c
static	char sccsid[] = "@(#)ifconfig.c 1.5 83/12/02 SMI"; /* from UCB 4.3 09/16/83 */
X.
w
!Funky!Stuff!
echo x - ioctl.h.diffs
sed 's/^X//' >ioctl.h.diffs <<'!Funky!Stuff!'
207a

#define	SIOCSARP	_IOW(i, 30, struct arpreq)	/* set arp entry */
#define	SIOCGARP	_IOWR(i, 31, struct arpreq)	/* get arp entry */
#define	SIOCDARP	_IOW(i, 32, struct arpreq)	/* delete arp entry */
X.
1c
/*	@(#)ioctl.h 1.4 83/11/29 SMI; from UCB 4.34 83/06/13	*/
X.
w
!Funky!Stuff!