Radix cross Linux

The main Radix cross Linux repository contains the build scripts of packages, which have the most complete and common functionality for desktop machines

452 Commits   2 Branches   1 Tag
Index: defs.h
===================================================================
--- defs.h	(nonexistent)
+++ defs.h	(revision 5)
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 1983, 1988, 1993
+ *	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 the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	from: @(#)defs.h	5.10 (Berkeley) 2/28/91
+ *	from: @(#)defs.h	8.1 (Berkeley) 6/5/93
+ *	$Id: defs.h,v 1.10 2000/12/25 14:56:55 jr Exp $
+ */
+
+/*
+ * Internal data structure definitions for
+ * user routing process.  Based on Xerox NS
+ * protocol specs with mods relevant to more
+ * general addressing scheme.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <protocols/routed.h>
+#include <arpa/inet.h>
+
+#include <netdb.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "trace.h"
+#include "interface.h"
+#include "table.h"
+#include "af.h"
+
+/*
+ * When we find any interfaces marked down we rescan the
+ * kernel every CHECK_INTERVAL seconds to see if they've
+ * come up.
+ */
+#define	CHECK_INTERVAL	(1*60)
+
+#define equal(a1, a2) \
+	(memcmp((a1), (a2), sizeof (struct sockaddr)) == 0)
+
+extern struct sockaddr_in addr;	/* address of daemon's socket */
+
+extern int sock;			/* source and sink of all data */
+extern int supplier;			/* process should supply updates */
+extern int ignoreptp;			/* whether to ignore PTP devices */
+extern int lookforinterfaces;	/* if 1 probe kernel for new up interfaces */
+extern struct iflist igniflist;		/* holds info about ignored devices */
+extern struct timeval now;		/* current idea of time */
+extern struct timeval lastbcast;	/* last time all/changes broadcast */
+extern struct timeval lastfullupdate;	/* last time full table broadcast */
+extern struct timeval nextbcast;    /* time to wait before changes broadcast */
+extern int needupdate;		    /* true if we need update at nextbcast */
+extern struct sockaddr_in inet_default;	/* default inet addr */
+extern int kernel_version;		/* kernel we are running under */
+
+extern char	packet[MAXPACKETSIZE+1];
+extern struct	rip *msg;
+
+extern int rip_port;              /* port number we use (network byte order) */
+
+void supply(struct sockaddr *, int, struct interface *, int);
+
+void addrouteforif __P((struct interface *));
+void bumploglevel(void);
+void dumppacket(FILE *, char *, struct sockaddr *, char *,int, struct timeval *);
+void gwkludge(void);
+void hup(int);
+void ifinit(void);
+int inet_maskof(u_long);
+u_long inet_netof_subnet(struct in_addr);
+int inet_rtflags(struct sockaddr *);
+int inet_sendroute(struct rt_entry *, struct sockaddr *);
+void quit(char *);
+int is_ignored(char *);
+void rip_input(struct sockaddr *, struct rip *, int);
+void rtadd(struct sockaddr *, struct sockaddr *, int, int);
+void rtchange(struct rt_entry *, struct sockaddr *, short);
+void rtdefault(void);
+void rtdelete(struct rt_entry *);
+void rtdeleteall(int);
+void rtinit(void);
+int rtioctl(int, struct rtuentry *);
+void sigtrace(int);
+void sndmsg(struct sockaddr *, int, struct interface *, int);
+void timer(int);
+void timevaladd(struct timeval *t1, struct timeval *t2);
+void timevalsub(struct timeval *t1, struct timeval *t2);
+void toall(void (*)(struct sockaddr *, int, struct interface *, int), 
+		int, struct interface *);
+void traceoff(void);
+void traceon(char *);
+void trace(struct ifdebug *, struct sockaddr *, char *, int, int);
+void traceaction(FILE *, char *, struct rt_entry *);
+void traceinit(struct interface *);
+void tracenewmetric(FILE *, struct rt_entry *, int);
+
+#define ADD 1
+#define DELETE 2
+#define CHANGE 3
+#define ROOT "root"
+#define NOBODY "nobody"
Index: inet.c
===================================================================
--- inet.c	(nonexistent)
+++ inet.c	(revision 5)
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 1983, 1993
+ *	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 the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * From: @(#)inet.c	5.8 (Berkeley) 6/1/90
+ * From: @(#)inet.c	8.2 (Berkeley) 8/14/93
+ */
+char inet_rcsid[] = 
+  "$Id: inet.c,v 1.6 2000/12/25 14:01:30 jr Exp $";
+
+
+/*
+ * Temporarily, copy these routines from the kernel,
+ * as we need to know about subnets.
+ */
+#include "defs.h"
+
+extern struct interface *ifnet;
+
+#if !defined(__GLIBC__) || (__GLIBC__ < 2)
+/*
+ * Formulate an Internet address from network + host.
+ */
+struct in_addr inet_makeaddr(u_long net, u_long host)
+{
+	struct interface *ifp;
+	u_long mask;
+	u_long addr;
+
+	if (IN_CLASSA(net))
+		mask = IN_CLASSA_HOST;
+	else if (IN_CLASSB(net))
+		mask = IN_CLASSB_HOST;
+	else
+		mask = IN_CLASSC_HOST;
+	for (ifp = ifnet; ifp; ifp = ifp->int_next)
+		if ((ifp->int_netmask & net) == ifp->int_net) {
+			mask = ~ifp->int_subnetmask;
+			break;
+		}
+	addr = net | (host & mask);
+	addr = htonl(addr);
+	return (*(struct in_addr *)&addr);
+}
+#endif /* not glibc */
+
+/*
+ * Return the network number from an internet address.
+ */
+u_long inet_netof_subnet(struct in_addr in)
+{
+	u_long i = ntohl(in.s_addr);
+	u_long net;
+	struct interface *ifp;
+
+	if (IN_CLASSA(i))
+		net = i & IN_CLASSA_NET;
+	else if (IN_CLASSB(i))
+		net = i & IN_CLASSB_NET;
+	else
+		net = i & IN_CLASSC_NET;
+
+	/*
+	 * Check whether network is a subnet;
+	 * if so, return subnet number.
+	 */
+	for (ifp = ifnet; ifp; ifp = ifp->int_next)
+		if ((ifp->int_netmask & net) == ifp->int_net)
+			return (i & ifp->int_subnetmask);
+	return (net);
+}
+
+/*
+ * Return the netmask pertaining to an internet address.
+ */
+
+int inet_maskof(u_long inaddr)
+{
+	u_long i = ntohl(inaddr);
+	u_long mask;
+	struct interface *ifp;
+
+	if (i == 0) {
+		mask = 0;
+	} else if (IN_CLASSA(i)) {
+		mask = IN_CLASSA_NET;
+	} else if (IN_CLASSB(i)) {
+		mask = IN_CLASSB_NET;
+	} else
+		mask = IN_CLASSC_NET;
+
+	/*
+	 * Check whether network is a subnet;
+	 * if so, use the modified interpretation of `host'.
+	 */
+	for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+		if (ifp->int_flags & IFF_POINTOPOINT)
+			continue;
+		if ((ifp->int_netmask & i) == ifp->int_net)
+			mask = ifp->int_subnetmask;
+	}
+	return (htonl(mask));
+}
+
+/*
+ * Return RTF_HOST if the address is
+ * for an Internet host, RTF_SUBNET for a subnet,
+ * 0 for a network.
+ */
+
+int inet_rtflags(struct sockaddr *sa)
+{
+	struct sockaddr_in *sin=(struct sockaddr_in *)sa;
+	u_long i = ntohl(sin->sin_addr.s_addr);
+	u_long net, host;
+	struct interface *ifp;
+
+	if (IN_CLASSA(i)) {
+		net = i & IN_CLASSA_NET;
+		host = i & IN_CLASSA_HOST;
+	} else if (IN_CLASSB(i)) {
+		net = i & IN_CLASSB_NET;
+		host = i & IN_CLASSB_HOST;
+	} else {
+		net = i & IN_CLASSC_NET;
+		host = i & IN_CLASSC_HOST;
+	}
+
+	/*
+	 * Check whether this network is subnetted;
+	 * if so, check whether this is a subnet or a host.
+	 */
+	for (ifp = ifnet; ifp; ifp = ifp->int_next)
+		if (net == ifp->int_net) {
+			if (host &~ ifp->int_subnetmask)
+				return (RTF_HOST);
+			else if (ifp->int_subnetmask != ifp->int_netmask)
+				return (RTF_SUBNET);
+			else
+				return (0);		/* network */
+		}
+	if (host == 0)
+		return (0);	/* network */
+	else
+		return (RTF_HOST);
+}
+
+/*
+ * Return true if a route to subnet/host of route rt should be sent to dst.
+ * Send it only if dst is on the same logical network if not "internal",
+ * otherwise only if the route is the "internal" route for the logical net.
+ */
+
+int inet_sendroute(struct rt_entry *rt, struct sockaddr *sa)
+{
+	struct sockaddr_in *dst=(struct sockaddr_in *)sa;
+	u_long r =
+	    ntohl(((struct sockaddr_in *)&rt->rt_dst)->sin_addr.s_addr);
+	u_long d = ntohl(dst->sin_addr.s_addr);
+
+	if (IN_CLASSA(r)) {
+		if ((r & IN_CLASSA_NET) == (d & IN_CLASSA_NET)) {
+			if ((r & IN_CLASSA_HOST) == 0)
+				return ((rt->rt_state & RTS_INTERNAL) == 0);
+			return (1);
+		}
+		if (r & IN_CLASSA_HOST)
+			return (0);
+		return ((rt->rt_state & RTS_INTERNAL) != 0);
+	} else if (IN_CLASSB(r)) {
+		if ((r & IN_CLASSB_NET) == (d & IN_CLASSB_NET)) {
+			if ((r & IN_CLASSB_HOST) == 0)
+				return ((rt->rt_state & RTS_INTERNAL) == 0);
+			return (1);
+		}
+		if (r & IN_CLASSB_HOST)
+			return (0);
+		return ((rt->rt_state & RTS_INTERNAL) != 0);
+	} else {
+		if ((r & IN_CLASSC_NET) == (d & IN_CLASSC_NET)) {
+			if ((r & IN_CLASSC_HOST) == 0)
+				return ((rt->rt_state & RTS_INTERNAL) == 0);
+			return (1);
+		}
+		if (r & IN_CLASSC_HOST)
+			return (0);
+		return ((rt->rt_state & RTS_INTERNAL) != 0);
+	}
+}
Index: interface.h
===================================================================
--- interface.h	(nonexistent)
+++ interface.h	(revision 5)
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 1983, 1993
+ *	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 the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	From: @(#)interface.h	5.6 (Berkeley) 6/1/90
+ *	From: @(#)interface.h	8.1 (Berkeley) 6/5/93
+ *	$Id: interface.h,v 1.8 2000/12/22 19:43:08 jr Exp $
+ */
+
+/*
+ * Routing table management daemon.
+ */
+
+/*
+ * iflist describes array of ignored interface names
+ */
+struct iflist {
+	u_long	length;
+	char	*array;
+};
+
+/*
+ * An ``interface'' is similar to an ifnet structure,
+ * except it doesn't contain q'ing info, and it also
+ * handles ``logical'' interfaces (remote gateways
+ * that we want to keep polling even if they go down).
+ * The list of interfaces which we maintain is used
+ * in supplying the gratuitous routing table updates.
+ */
+struct interface {
+	struct	interface *int_next;
+	struct	sockaddr int_addr;		/* address on this host */
+	union {
+		struct	sockaddr intu_broadaddr;
+		struct	sockaddr intu_dstaddr;
+	} int_intu;
+#define	int_broadaddr	int_intu.intu_broadaddr	/* broadcast address */
+#define	int_dstaddr	int_intu.intu_dstaddr	/* other end of p-to-p link */
+	int	int_metric;			/* init's routing entry */
+	int	int_flags;			/* see below */
+	/* START INTERNET SPECIFIC */
+	u_long	int_net;			/* network # */
+	u_long	int_netmask;			/* net mask for addr */
+	u_long	int_subnet;			/* subnet # */
+	u_long	int_subnetmask;			/* subnet mask for addr */
+	/* END INTERNET SPECIFIC */
+	struct	ifdebug int_input, int_output;	/* packet tracing stuff */
+	int	int_ipackets;			/* input packets received */
+	int	int_opackets;			/* output packets sent */
+	char	*int_name;			/* from kernel if structure */
+	u_short	int_transitions;		/* times gone up-down */
+};
+
+#if defined(__GLIBC__) && (__GLIBC__ >= 2)
+#include <net/if.h>
+#else /* not glibc */
+
+/*
+ * 0x1 to 0x10 are reused from the kernel's ifnet definitions,
+ * the others agree with the RTS_ flags defined elsewhere.
+ */
+#define	IFF_UP		0x1		/* interface is up */
+#define	IFF_BROADCAST	0x2		/* broadcast address valid */
+#define	IFF_DEBUG	0x4		/* turn on debugging */
+#define	IFF_LOOPBACK	0x8		/* software loopback net */
+#define	IFF_POINTOPOINT	0x10		/* interface is point-to-point link */
+
+#endif /* glibc/not glibc */
+
+#define	IFF_SUBNET	0x100000	/* interface on subnetted network */
+#define	IFF_PASSIVE	0x200000	/* can't tell if up/down */
+#define	IFF_INTERFACE	0x400000	/* hardware interface */
+#define	IFF_REMOTE	0x800000	/* interface isn't on this machine */
+
+extern struct interface *ifnet;
+
+struct	interface *if_ifwithaddr(struct sockaddr *);
+struct	interface *if_ifwithdstaddr(struct sockaddr *);
+struct	interface *if_ifwithnet(struct sockaddr *);
+struct	interface *if_iflookup(struct sockaddr *);
Index: main.c
===================================================================
--- main.c	(nonexistent)
+++ main.c	(revision 5)
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 1983, 1988, 1993
+ *	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 the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+char copyright[] =
+  "@(#) Copyright (c) 1983, 1988, 1993\n"
+  "      The Regents of the University of California.  All rights reserved.\n";
+
+/*
+ * From: @(#)main.c	5.23 (Berkeley) 7/1/91
+ * From: @(#)main.c	8.1 (Berkeley) 6/5/93
+ */
+char main_rcsid[] = 
+  "$Id: main.c,v 1.17 2000/12/23 18:07:39 jr Exp $";
+
+#include "../version.h"
+#include <time.h>
+
+/*
+ * Routing Table Management Daemon
+ */
+
+#include "defs.h"
+#include <sys/ioctl.h>
+#include <sys/file.h>
+
+#include <errno.h>
+/* #include <signal.h>  (redundant with defs.h) */
+#include <syslog.h>
+#include <assert.h>
+#include <sys/utsname.h>
+
+#define BUFSPACE (127*1024)	/* max. input buffer size to request */
+
+struct sockaddr_in addr;	/* address of daemon's socket */
+int sock;			/* source and sink of all data */
+char	packet[MAXPACKETSIZE+1];
+int rip_port;
+
+int	supplier = -1;		/* process should supply updates */
+int	gateway = 0;		/* 1 if we are a gateway to parts beyond */
+int	debug = 0;
+int	ignoreptp = 0;
+struct	iflist igniflist;
+struct	rip *msg = (struct rip *)packet;
+int	kernel_version;
+
+static void getkversion(void);
+static int getsocket(void);
+static void process(int);
+void addignoredif(char *);
+
+int
+main(int argc, char *argv[])
+{
+	int n, nfd, tflags = 0, ch;
+	struct timeval *tvp, waittime;
+	struct itimerval itval;
+	struct rip *query = msg;
+	fd_set ibits;
+	sigset_t sigset, osigset;
+
+	memset(&igniflist, 0, sizeof(struct iflist));
+	while ((ch = getopt(argc, argv, "sqtdgpi:")) != EOF) {
+		switch (ch) {
+			case 's': supplier = 1; break;
+			case 'q': supplier = 0; break;
+			case 't': 
+				tflags++;
+				break;
+			case 'd': 
+				debug++;
+				setlogmask(LOG_UPTO(LOG_DEBUG));
+				break;
+			case 'g': gateway = 1; break;
+			case 'p': ignoreptp = 1; break;
+			case 'i':
+				addignoredif(optarg);
+				break;
+			default:
+				fprintf(stderr, "usage: routed [ -sqtdgp ] [ -i device ]\n");
+				exit(1);
+		}
+	}
+
+	getkversion();
+
+	sock = getsocket();
+	assert(sock>=0);
+
+	openlog("routed", LOG_PID | LOG_ODELAY, LOG_DAEMON);
+
+	if (debug == 0 && tflags == 0) {
+		switch (fork()) {
+			case -1: perror("fork"); exit(1);
+			case 0: break;   /* child */
+			default: exit(0);  /* parent */
+		}
+		close(0);
+		close(1);
+		close(2);
+		setsid();
+		setlogmask(LOG_UPTO(LOG_WARNING));
+	}
+	else {
+		setlogmask(LOG_UPTO(LOG_DEBUG));
+	}
+
+	/*
+	 * Any extra argument is considered
+	 * a tracing log file.
+	 * 
+	 * Note: because traceon() redirects stderr, anything planning to
+	 * crash on startup should do so before this point.
+	 */
+
+	if (argc > optind) {
+		traceon(argv[optind]);
+	}
+	while (tflags-- > 0) {
+		bumploglevel();
+	}
+
+	gettimeofday(&now, NULL);
+
+	/*
+	 * Collect an initial view of the world by
+	 * checking the interface configuration and the gateway kludge
+	 * file.  Then, send a request packet on all
+	 * directly connected networks to find out what
+	 * everyone else thinks.
+	 */
+
+	rtinit();
+	ifinit();
+	gwkludge();
+	if (gateway > 0) {
+		rtdefault();
+	}
+	if (supplier < 0) {
+		supplier = 0;
+	}
+	query->rip_cmd = RIPCMD_REQUEST;
+	query->rip_vers = RIPVERSION;
+	if (sizeof(query->rip_nets[0].rip_dst.sa_family) > 1) {
+		/* XXX */
+		query->rip_nets[0].rip_dst.sa_family = htons((u_short)AF_UNSPEC);
+	}
+	else {
+		/* unreachable code (at least on most platforms) */
+		query->rip_nets[0].rip_dst.sa_family = AF_UNSPEC;
+	}
+	query->rip_nets[0].rip_metric = htonl((u_long)HOPCNT_INFINITY);
+
+	toall(sndmsg, 0, NULL);
+
+	signal(SIGALRM, timer);
+	signal(SIGHUP, hup);
+	signal(SIGTERM, hup);
+	signal(SIGINT, rtdeleteall);
+	signal(SIGUSR1, sigtrace);
+	signal(SIGUSR2, sigtrace);
+
+	itval.it_interval.tv_sec = TIMER_RATE;
+	itval.it_value.tv_sec = TIMER_RATE;
+	itval.it_interval.tv_usec = 0;
+	itval.it_value.tv_usec = 0;
+
+	srandom(time(NULL) ^ getpid());
+
+	if (setitimer(ITIMER_REAL, &itval, (struct itimerval *)NULL) < 0) {
+		syslog(LOG_ERR, "setitimer: %m\n");
+	}
+
+	FD_ZERO(&ibits);
+	nfd = sock + 1;			/* 1 + max(fd's) */
+	for (;;) {
+		FD_SET(sock, &ibits);
+
+		/*
+		 * If we need a dynamic update that was held off,
+		 * needupdate will be set, and nextbcast is the time
+		 * by which we want select to return.  Compute time
+		 * until dynamic update should be sent, and select only
+		 * until then.  If we have already passed nextbcast,
+		 * just poll.
+		 */
+		if (needupdate) {
+			waittime = nextbcast;
+			timevalsub(&waittime, &now);
+			if (waittime.tv_sec < 0) {
+				waittime.tv_sec = 0;
+				waittime.tv_usec = 0;
+			}
+			if (traceactions)
+				fprintf(ftrace,
+				 "select until dynamic update %ld/%ld sec/usec\n",
+				    (long)waittime.tv_sec, (long)waittime.tv_usec);
+			tvp = &waittime;
+		}
+		else {
+			tvp = (struct timeval *)NULL;
+		}
+
+		n = select(nfd, &ibits, 0, 0, tvp);
+		if (n <= 0) {
+			/*
+			 * Need delayed dynamic update if select returned
+			 * nothing and we timed out.  Otherwise, ignore
+			 * errors (e.g. EINTR).
+			 */
+			if (n < 0) {
+				if (errno == EINTR)
+					continue;
+				syslog(LOG_ERR, "select: %m");
+			}
+			sigemptyset(&sigset);
+			sigaddset(&sigset, SIGALRM);
+			sigprocmask(SIG_BLOCK, &sigset, &osigset);
+			if (n == 0 && needupdate) {
+				if (traceactions)
+					fprintf(ftrace,
+					    "send delayed dynamic update\n");
+				(void) gettimeofday(&now,
+					    (struct timezone *)NULL);
+				toall(supply, RTS_CHANGED,
+				    (struct interface *)NULL);
+				lastbcast = now;
+				needupdate = 0;
+				nextbcast.tv_sec = 0;
+			}
+			sigprocmask(SIG_SETMASK, &osigset, NULL);
+			continue;
+		}
+
+		gettimeofday(&now, (struct timezone *)NULL);
+		sigemptyset(&sigset);
+		sigaddset(&sigset, SIGALRM);
+		sigprocmask(SIG_BLOCK, &sigset, &osigset);
+
+		if (FD_ISSET(sock, &ibits)) {
+			process(sock);
+		}
+
+		/* handle ICMP redirects */
+		sigprocmask(SIG_SETMASK, &osigset, NULL);
+	}
+}
+
+/*
+ * Put Linux kernel version into
+ * the global variable kernel_version.
+ * Example: 1.2.8 = 0x010208
+ */
+
+static
+void
+getkversion(void)
+{
+	struct utsname uts;
+	int maj, min, pl;
+
+	maj = min = pl = 0;
+	uname(&uts);
+	sscanf(uts.release, "%d.%d.%d", &maj, &min, &pl);
+	kernel_version = (maj << 16) | (min << 8) | pl;
+}
+
+void
+timevaladd(struct timeval *t1, struct timeval *t2)
+{
+
+	t1->tv_sec += t2->tv_sec;
+	if ((t1->tv_usec += t2->tv_usec) > 1000000) {
+		t1->tv_sec++;
+		t1->tv_usec -= 1000000;
+	}
+}
+
+void
+timevalsub(struct timeval *t1, struct timeval *t2)
+{
+
+	t1->tv_sec -= t2->tv_sec;
+	if ((t1->tv_usec -= t2->tv_usec) < 0) {
+		t1->tv_sec--;
+		t1->tv_usec += 1000000;
+	}
+}
+
+static
+void
+process(int fd)
+{
+	struct sockaddr from;
+	socklen_t fromlen;
+	int cc;
+	union {
+		char	buf[MAXPACKETSIZE+1];
+		struct	rip rip;
+	} inbuf;
+
+	for (;;) {
+		fromlen = sizeof(from);
+		cc = recvfrom(fd, &inbuf, sizeof(inbuf), 0, &from, &fromlen);
+		if (cc <= 0) {
+			if (cc < 0 && errno != EWOULDBLOCK)
+				perror("recvfrom");
+			break;
+		}
+		if (fromlen != sizeof (struct sockaddr_in)) {
+			break;
+		}
+		rip_input(&from, &inbuf.rip, cc);
+	}
+}
+
+/*
+ * This function is called during startup, and should error to stderr,
+ * not syslog, and should exit on error.
+ */
+static
+int
+getsocket(void)
+{
+	int s, on = 1;
+	struct servent *sp;
+
+	sp = getservbyname("router", "udp");
+	if (sp == NULL) {
+		fprintf(stderr, "routed: router/udp: unknown service\n");
+		exit(1);
+	}
+	rip_port = sp->s_port;
+
+	s = socket(AF_INET, SOCK_DGRAM, 0);
+	if (s < 0) {
+		perror("socket");
+		exit(1);
+	}
+
+#ifdef SO_BROADCAST
+	if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
+		perror("setsockopt SO_BROADCAST");
+		exit(1);
+	}
+#endif
+
+#ifdef SO_RCVBUF
+	on = BUFSPACE;
+	while (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on))) {
+		if (on <= 8192) {
+			/* give up */
+			perror("setsockopt SO_RCVBUF");
+			break;
+		}
+		/* try 1k less */
+		on -= 1024;
+	}
+	if (traceactions) {
+		fprintf(ftrace, "recv buf %d\n", on);
+	}
+#endif
+
+	addr.sin_family = AF_INET;
+	addr.sin_port = rip_port;
+
+	if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+		perror("bind");
+		close(s);
+		exit(1);
+	}
+
+	if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) {
+		perror("fcntl O_NONBLOCK");
+	}
+
+	return (s);
+}
+
+/*
+ * Add single interface name to the list of ignored interface names.
+ */
+void
+addignoredif(char *ifn)
+{
+	char *ifl = NULL;
+
+	/* avoiding realloc() */
+	ifl = calloc(1, igniflist.length * IFNAMSIZ + IFNAMSIZ);
+	if (ifl == NULL) {
+		syslog(LOG_ERR, "routed: addignoredif: out of memory\n");
+		return;
+	}
+	memcpy(ifl, igniflist.array, igniflist.length * IFNAMSIZ);
+	memcpy(ifl + igniflist.length++ * IFNAMSIZ,
+		ifn,
+		strlen(ifn) >= IFNAMSIZ ? IFNAMSIZ - 1 : strlen (ifn));
+	if (igniflist.array != NULL)
+		free(igniflist.array);
+	igniflist.array = ifl;
+}
Index: routed.8
===================================================================
--- routed.8	(nonexistent)
+++ routed.8	(revision 5)
@@ -0,0 +1,433 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\"	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 the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     From: @(#)routed.8	6.6 (Berkeley) 3/16/91
+.\"	From: @(#)routed.8	8.2 (Berkeley) 12/11/93
+.\"	From: NetBSD: routed.8,v 1.6 1995/03/18 15:00:38 cgd Exp
+.\"	$Id: routed.8,v 1.16 2000/12/25 14:36:27 jr Exp $
+.\"
+.Dd December 11, 1993
+.Dt ROUTED 8
+.Os "Linux NetKit (0.18)"
+.Sh NAME
+.Nm routed
+.Nd network routing daemon
+.Sh SYNOPSIS
+.Nm routed
+.Op Fl d
+.Op Fl g
+.Op Fl s
+.Op Fl q
+.Op Fl t
+.Op Fl p
+.Op Fl i Nm device
+.Op Ar logfile
+.Sh DESCRIPTION
+.Nm Routed
+is invoked at boot time to manage the network routing tables.
+The routing daemon uses a variant of the Xerox NS Routing
+Information Protocol in maintaining up to date kernel routing
+table entries.
+It used a generalized protocol capable of use with multiple
+address types, but is currently used only for Internet routing
+within a cluster of networks.
+.Pp
+In normal operation
+.Nm routed
+listens on the
+.Xr udp 4
+socket for the
+.Xr route 8
+service (see
+.Xr services 5 )
+for routing information packets.  If the host is an
+internetwork router, it periodically supplies copies
+of its routing tables to any directly connected hosts
+and networks.
+.Pp
+When
+.Nm routed
+is started, it uses the
+.Dv SIOCGIFCONF
+.Xr ioctl 2
+to find those
+directly connected interfaces configured into the
+system and marked ``up'' (the software loopback interface
+is ignored).  If multiple interfaces
+are present, it is assumed that the host will forward packets
+between networks.
+.Nm Routed
+then transmits a 
+.Em request
+packet on each interface (using a broadcast packet if
+the interface supports it) and enters a loop, listening
+for
+.Em request
+and
+.Em response
+packets from other hosts.
+.Pp
+When a
+.Em request
+packet is received, 
+.Nm routed
+formulates a reply based on the information maintained in its
+internal tables.  The
+.Em response
+packet generated contains a list of known routes, each marked
+with a ``hop count'' metric (a count of 16, or greater, is
+considered ``infinite'').  The metric associated with each
+route returned provides a metric
+.Em relative to the sender .
+.Pp
+.Em Response
+packets received by
+.Nm routed
+are used to update the routing tables if one of the following
+conditions is satisfied:
+.Bl -enum
+.It
+No routing table entry exists for the destination network
+or host, and the metric indicates the destination is ``reachable''
+(i.e. the hop count is not infinite).
+.It
+The source host of the packet is the same as the router in the
+existing routing table entry.  That is, updated information is
+being received from the very internetwork router through which
+packets for the destination are being routed.
+.It
+The existing entry in the routing table has not been updated for
+some time (defined to be 90 seconds) and the route is at least
+as cost effective as the current route.
+.It
+The new route describes a shorter route to the destination than
+the one currently stored in the routing tables; the metric of
+the new route is compared against the one stored in the table
+to decide this.
+.El
+.Pp
+When an update is applied,
+.Nm routed
+records the change in its internal tables and updates the kernel
+routing table.
+The change is reflected in the next
+.Em response
+packet sent.
+.Pp
+In addition to processing incoming packets,
+.Nm routed
+also periodically checks the routing table entries.
+If an entry has not been updated for 3 minutes, the entry's metric
+is set to infinity and marked for deletion.  Deletions are delayed
+an additional 60 seconds to insure the invalidation is propagated
+throughout the local internet.
+.Pp
+Hosts acting as internetwork routers gratuitously supply their
+routing tables every 30 seconds to all directly connected hosts
+and networks.
+The response is sent to the broadcast address on nets capable of that function,
+to the destination address on point-to-point links, and to the router's
+own address on other networks.
+The normal routing tables are bypassed when sending gratuitous responses.
+The reception of responses on each network is used to determine that the
+network and interface are functioning correctly.
+If no response is received on an interface, another route may be chosen
+to route around the interface, or the route may be dropped if no alternative
+is available.
+.Pp
+Options supported by
+.Nm routed :
+.Bl -tag -width Ds
+.It Fl d
+Enable additional debugging information to be logged,
+such as bad packets received.
+.It Fl g
+This flag is used on internetwork routers to offer a route
+to the ``default'' destination.
+This is typically used on a gateway to the Internet,
+or on a gateway that uses another routing protocol whose routes
+are not reported to other local routers.
+.It Fl s
+Supplying this
+option forces 
+.Nm routed
+to supply routing information that it is acting as an internetwork
+router.
+This is the default if multiple network interfaces are present,
+or if a point-to-point link is in use.
+.It Fl q
+This
+is the opposite of the
+.Fl s
+option.
+.It Fl t
+If the
+.Fl t
+option is specified, all packets sent or received are
+printed on the standard output.  In addition,
+.Nm routed
+will not divorce itself from the controlling terminal
+so that interrupts from the keyboard will kill the process.
+.It Fl p
+this option forces
+.Nm routed
+to ignore existence of all point-to-point network interfaces.
+.Nm Routed
+wont send nor receive routing updates through these interfaces
+and also wont propagate corresponding routes to remote endpoints directly
+reachable through them. Sometimes it is not desirable to send/receive
+routing information about routes through such interfaces, for example
+when point-to-point link with proxy-arp is in use.
+.It Fl i Nm dev
+this option forces
+.Nm routed
+to ignore existence of a specified network interface
+.Nm dev .
+Similarly to
+.Fl p
+flag, routed wont send nor receive routing updates through
+.Nm dev ,
+nor it will advertise direct routes via such interface.
+.El
+.Pp
+Any other argument supplied is interpreted as the full path to and name
+of file in which 
+.Nm routed Ns \'s
+actions should be logged.  This log contains information
+about any changes to the routing tables and, if not tracing all packets,
+a history of recent messages sent and received which are related to
+the changed route.
+With first event to be logged,
+.Nm routed
+will create log file in "/var/log/routed" directory (which has to
+exist and be readable/writeable only by root). For security reasons,
+this argument has to begin with "/var/log/routed", as
+.Nm routed
+itself does not perform other security checks towards validity of the
+remote traceon/traceoff requests it may receive. Unless
+for debugging purposes, it is strongly recommended that the logging
+path itself does not exist nor is specified as
+.Nm routed
+parameter at all.
+.Pp
+In addition to the facilities described above, 
+.Nm routed
+supports the notion of ``distant''
+.Em passive
+, 
+.Em active
+, 
+.Em external
+and 
+.Em announced
+gateway types.  When 
+.Nm routed
+is started up, it reads the file
+.Pa /etc/gateways
+to find gateways which may not be located using
+only information from the
+.Dv SIOGIFCONF
+.Xr ioctl 2 .
+Gateways specified in this manner should be marked passive
+if they are not expected to exchange routing information,
+while gateways marked active
+should be willing to exchange routing information (i.e.
+they should have a
+.Nm routed
+process running on the machine).
+.Pp
+Routes through
+.Nm passive
+gateways are installed in the
+kernel's routing tables by
+.Nm routed
+once upon its startup. Such routes are not included
+in any routing information transmitted.
+.Pp
+.Nm Active
+gateways are treated equally to network
+interfaces.  Routing information is distributed
+to the gateway and
+.Nm routed
+listens for updates on the interface that the gateway is
+reachable through.
+.Pp
+Gateways marked
+.Nm external
+are also passive, but are not placed in the kernel
+routing table nor are they included in routing updates.
+The function of
+.Nm external
+entries is to inform
+.Nm routed
+that another routing process
+will install such a route, so that it should not install
+alternate routes to that destination.
+Such entries are only required when both routers may learn of routes
+to the same destination.
+.Pp
+Routes to networks through gateways marked as
+.Nm announced
+will be included in each routing advertisement, but won't be installed
+in the kernel routing table. This kind of entries is only required
+for the gateways that are directly reachable, but are unable
+to announce their routes, so that the rest of the RIP1 protocol-equipped
+network will know about such routes too. Entries of
+.Nm announced
+type can also be used to announce direct routes for own interfaces, that
+didn't exist at the time when
+.Nm routed
+has been started, but can be expected to come up later
+(such as routes for point-to-point interfaces).
+.Pp
+The 
+.Pa /etc/gateways
+is comprised of a series of lines, each in
+the following format:
+.Bd -ragged
+.Pf < Cm net No \&|
+.Cm host Ns >
+.Ar name1
+.Cm gateway
+.Ar name2
+.Cm metric
+.Ar value
+.Pf < Cm passive No \&|
+.Cm active No \&|
+.Cm external No \&|
+.Cm announced Ns >
+.Ed
+.Pp
+The 
+.Cm net
+or
+.Cm host
+keyword indicates if the route is to a network or specific host.
+.Pp
+.Ar Name1
+is the name of the destination network or host.  This may be a
+symbolic name located in
+.Pa /etc/networks
+or
+.Pa /etc/hosts
+(or, if started after
+.Xr named 8 ,
+known to the name server), 
+or an Internet address specified in ``dot'' notation; see
+.Xr inet 3 .
+.Pp
+.Ar Name2
+is the name or address of the gateway to which messages should
+be forwarded.
+.Pp
+.Ar Value
+is a metric indicating the hop count to the destination host
+or network.
+.Pp
+One of the keywords
+.Cm passive ,
+.Cm active ,
+.Cm external
+or
+.Cm announced
+indicates if the gateway should be treated as 
+.Em passive
+or
+.Em active
+(as described above),
+whether the gateway is
+.Em external
+to the scope of the
+.Nm routed
+protocol, or whether
+the route reachable via such gateway should
+be included in the routing table announcements.
+.Pp
+Internetwork routers that are directly attached to the Arpanet or Milnet
+should use the Exterior Gateway Protocol
+.Pq Tn EGP
+to gather routing information
+rather than using a static routing table of passive gateways.
+.Tn EGP
+is required in order to provide routes for local networks to the rest
+of the Internet system.
+.Sh FILES
+.Bl -tag -width /etc/gateways -compact
+.It Pa /etc/gateways
+for distant gateways
+.El
+.Sh SEE ALSO
+.Xr udp 7 ,
+.Xr icmp 7 .
+.Rs
+.%T Internet Transport Protocols
+.%R XSIS 028112
+.%Q Xerox System Integration Standard
+.Re
+.Sh BUGS
+.Pp
+.Nm Routed
+is heavily 32bit architecture dependant. You should eventually
+consider using
+.Xr gated 8
+or
+.Xr zebra 8 .
+.Pp
+The kernel's routing tables may not correspond to those of
+.Nm routed
+when redirects change or add routes.
+.Nm Routed
+should note any redirects received by reading
+the
+.Tn ICMP
+packets received via a raw socket.
+.Pp
+.Nm Routed
+also doesn't notice of any new interface, that didn't exist prior to
+its start, but has newly appeared and come to ``up'' state after
+routed has been started, and won't announce route for such interface.
+.Pp
+.Nm Routed
+should incorporate other routing protocols.
+Using separate processes for each requires configuration options
+to avoid redundant or competing routes.
+.Pp
+.Nm Routed
+should listen to intelligent interfaces, such as an
+.Tn IMP ,
+to gather more information.
+It does not always detect unidirectional failures in network interfaces
+(e.g., when the output side fails).
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
Index: startup.c
===================================================================
--- startup.c	(nonexistent)
+++ startup.c	(revision 5)
@@ -0,0 +1,545 @@
+/*
+ * Copyright (c) 1983, 1988, 1993
+ *	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 the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * From: @(#)startup.c	5.19 (Berkeley) 2/28/91
+ * From: @(#)startup.c	8.1 (Berkeley) 6/5/93
+ */
+char startup_rcsid[] = 
+  "$Id: startup.c,v 1.11 2000/12/25 14:32:34 jr Exp $";
+
+
+/*
+ * Routing Table Management Daemon
+ */
+
+#include "defs.h"
+#include <sys/ioctl.h>
+/* #include <net/if.h> (redundant with defs.h) */
+#include <syslog.h>
+#include <errno.h>
+#include "pathnames.h"
+
+struct	interface *ifnet;
+struct	interface **ifnext = &ifnet;
+int	lookforinterfaces = 1;
+int	foundloopback;			/* valid flag for loopaddr */
+struct	sockaddr loopaddr;		/* our address on loopback */
+
+static int externalinterfaces = 0;	/* # of remote and local interfaces */
+
+void add_ptopt_localrt(struct interface *);
+int getnetorhostname(char *, char *, struct sockaddr_in *);
+int gethostnameornumber(char *, struct sockaddr_in *);
+
+void quit(char *s)
+{
+	int sverrno = errno;
+
+	(void) fprintf(stderr, "route: ");
+	if (s)
+		(void) fprintf(stderr, "%s: ", s);
+	(void) fprintf(stderr, "%s\n", strerror(sverrno));
+	exit(1);
+}
+
+int is_ignored(char *ifname)
+{
+	u_long i;
+
+	for (i = 0; i < igniflist.length; i++)
+		if (!(strcmp(ifname, igniflist.array + i * IFNAMSIZ)) )
+			return (1);
+
+	return (0);
+}
+
+#define ROUNDUP(a) \
+	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+
+/*
+ * Find the network interfaces which have configured themselves.
+ * If the interface is present but not yet up (for example an
+ * ARPANET IMP), set the lookforinterfaces flag so we'll
+ * come back later and look again.
+ */
+
+void ifinit(void)
+{
+	struct interface ifs, *ifp;
+	int s, maxifaces = 16;
+	char *cp;
+        struct ifconf ifc;
+        struct ifreq ifreq, *ifr;
+        struct sockaddr_in *sin;
+	u_long i;
+
+	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+		syslog(LOG_ERR, "socket: %m");
+		close(s);
+                return;
+	}
+	for (;;) {
+		ifc.ifc_len = sizeof(struct ifreq) * maxifaces;
+		ifc.ifc_buf = malloc(ifc.ifc_len);
+		if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
+			syslog(LOG_ERR, "ioctl (get interface configuration)");
+			return;
+		}
+		/*
+		 * Assume overflow (more interfaces). Increase size/repeat.
+		 */
+		if (ifc.ifc_len == (int) sizeof(struct ifreq) * maxifaces) {
+			maxifaces += 16;
+			free(ifc.ifc_buf);
+			continue;
+		}
+		break;
+        }
+	lookforinterfaces = 0;
+	for (cp = ifc.ifc_buf; cp < (ifc.ifc_buf + ifc.ifc_len);
+			cp += sizeof(struct ifreq)) {
+		ifr = (struct ifreq *)cp;
+		bzero((char *)&ifs, sizeof(ifs));
+		ifs.int_addr = ifr->ifr_addr;
+		ifreq = *ifr;
+                if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
+                        syslog(LOG_ERR, "%s: ioctl (get interface flags)",
+			    ifr->ifr_name);
+                        continue;
+                }
+		ifs.int_flags =
+		    ifreq.ifr_flags | IFF_INTERFACE;
+		if ((ifs.int_flags & IFF_UP) == 0 ||
+		    ifr->ifr_addr.sa_family == AF_UNSPEC) {
+			lookforinterfaces = 1;
+			continue;
+		}
+		/* argh, this'll have to change sometime */
+		if (ifs.int_addr.sa_family != AF_INET)
+			continue;
+		if (is_ignored(ifr->ifr_name))
+			continue;
+                if (ifs.int_flags & IFF_POINTOPOINT) {
+			if (ignoreptp)
+				continue;
+                        if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
+                                syslog(LOG_ERR, "%s: ioctl (get dstaddr)",
+				    ifr->ifr_name);
+                                continue;
+			}
+			if (ifr->ifr_addr.sa_family == AF_UNSPEC) {
+				lookforinterfaces = 1;
+				continue;
+			}
+			ifs.int_dstaddr = ifreq.ifr_dstaddr;
+		}
+		/*
+		 * already known to us?
+		 * This allows multiple point-to-point links
+		 * to share a source address (possibly with one
+		 * other link), but assumes that there will not be
+		 * multiple links with the same destination address.
+		 */
+		if (ifs.int_flags & IFF_POINTOPOINT) {
+			if (if_ifwithdstaddr(&ifs.int_dstaddr))
+				continue;
+		} else if (if_ifwithaddr(&ifs.int_addr))
+			continue;
+		if (ifs.int_flags & IFF_LOOPBACK) {
+			ifs.int_flags |= IFF_PASSIVE;
+			foundloopback = 1;
+			loopaddr = ifs.int_addr;
+			for (ifp = ifnet; ifp; ifp = ifp->int_next)
+			    if (ifp->int_flags & IFF_POINTOPOINT)
+				add_ptopt_localrt(ifp);
+		}
+                if (ifs.int_flags & IFF_BROADCAST) {
+                        if (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
+                                syslog(LOG_ERR, "%s: ioctl (get broadaddr)",
+				    ifr->ifr_name);
+                                continue;
+                        }
+			ifs.int_broadaddr = ifreq.ifr_broadaddr;
+		}
+#ifdef SIOCGIFMETRIC
+		if (ioctl(s, SIOCGIFMETRIC, (char *)&ifreq) < 0) {
+			syslog(LOG_ERR, "%s: ioctl (get metric)",
+			    ifr->ifr_name);
+			ifs.int_metric = 0;
+		} else
+			ifs.int_metric = ifreq.ifr_metric;
+#else
+		ifs.int_metric = 0;
+#endif
+		/*
+		 * Use a minimum metric of one;
+		 * treat the interface metric (default 0)
+		 * as an increment to the hop count of one.
+		 */
+		ifs.int_metric++;
+		if (ioctl(s, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
+			syslog(LOG_ERR, "%s: ioctl (get netmask)",
+			    ifr->ifr_name);
+			continue;
+		}
+		sin = (struct sockaddr_in *)&ifreq.ifr_addr;
+		ifs.int_subnetmask = ntohl(sin->sin_addr.s_addr);
+		sin = (struct sockaddr_in *)&ifs.int_addr;
+		i = ntohl(sin->sin_addr.s_addr);
+		if (IN_CLASSA(i))
+			ifs.int_netmask = IN_CLASSA_NET;
+		else if (IN_CLASSB(i))
+			ifs.int_netmask = IN_CLASSB_NET;
+		else
+			ifs.int_netmask = IN_CLASSC_NET;
+		ifs.int_net = i & ifs.int_netmask;
+		ifs.int_subnet = i & ifs.int_subnetmask;
+		if (ifs.int_subnetmask != ifs.int_netmask)
+			ifs.int_flags |= IFF_SUBNET;
+		ifp = (struct interface *)malloc(sizeof (struct interface));
+		if (ifp == 0) {
+			printf("routed: out of memory\n");
+			break;
+		}
+		*ifp = ifs;
+		/*
+		 * Count the # of directly connected networks
+		 * and point to point links which aren't looped
+		 * back to ourself.  This is used below to
+		 * decide if we should be a routing ``supplier''.
+		 */
+		if ((ifs.int_flags & IFF_LOOPBACK) == 0 &&
+		    ((ifs.int_flags & IFF_POINTOPOINT) == 0 ||
+		    if_ifwithaddr(&ifs.int_dstaddr) == 0))
+			externalinterfaces++;
+		/*
+		 * If we have a point-to-point link, we want to act
+		 * as a supplier even if it's our only interface,
+		 * as that's the only way our peer on the other end
+		 * can tell that the link is up.
+		 */
+		if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0)
+			supplier = 1;
+		ifp->int_name = malloc(strlen(ifr->ifr_name) + 1);
+		if (ifp->int_name == NULL) {
+			fprintf(stderr, "routed: ifinit: out of memory\n");
+			syslog(LOG_ERR, "routed: ifinit: out of memory\n");
+			goto escape;
+		}
+		strcpy(ifp->int_name, ifr->ifr_name);
+		*ifnext = ifp;
+		ifnext = &ifp->int_next;
+		traceinit(ifp);
+		addrouteforif(ifp);
+	}
+	if (externalinterfaces > 1 && supplier < 0)
+		supplier = 1;
+escape:
+	free(ifc.ifc_buf);
+	close(s);
+	return;
+}
+
+/*
+ * Add route for interface if not currently installed.
+ * Create route to other end if a point-to-point link,
+ * otherwise a route to this (sub)network.
+ * INTERNET SPECIFIC.
+ */
+
+void addrouteforif(struct interface *ifp)
+{
+	struct sockaddr_in net;
+	struct sockaddr *dst;
+	int state;
+	struct rt_entry *rt;
+
+	if (ifp->int_flags & IFF_POINTOPOINT)
+		dst = &ifp->int_dstaddr;
+	else {
+		memset(&net, 0, sizeof (net));
+		net.sin_family = AF_INET;
+		net.sin_addr = inet_makeaddr(ifp->int_subnet, INADDR_ANY);
+		dst = (struct sockaddr *)&net;
+	}
+	rt = rtfind(dst);
+	if (rt &&
+	    (rt->rt_state & (RTS_INTERFACE | RTS_INTERNAL)) == RTS_INTERFACE)
+		return;
+	if (rt)
+		rtdelete(rt);
+	/*
+	 * If interface on subnetted network,
+	 * install route to network as well.
+	 * This is meant for external viewers.
+	 */
+	if ((ifp->int_flags & (IFF_SUBNET|IFF_POINTOPOINT)) == IFF_SUBNET) {
+		struct in_addr subnet;
+
+		subnet = net.sin_addr;
+		net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY);
+		rt = rtfind(dst);
+		if (rt == 0)
+			rtadd(dst, &ifp->int_addr, ifp->int_metric,
+			    ((ifp->int_flags & (IFF_INTERFACE|IFF_REMOTE)) |
+			    RTS_PASSIVE | RTS_INTERNAL | RTS_SUBNET));
+		else if ((rt->rt_state & (RTS_INTERNAL|RTS_SUBNET)) == 
+		    (RTS_INTERNAL|RTS_SUBNET) &&
+		    ifp->int_metric < rt->rt_metric)
+			rtchange(rt, &rt->rt_router, ifp->int_metric);
+		net.sin_addr = subnet;
+	}
+	if (ifp->int_transitions++ > 0)
+		syslog(LOG_ERR, "re-installing interface %s", ifp->int_name);
+	state = ifp->int_flags &
+	    (IFF_INTERFACE | IFF_PASSIVE | IFF_REMOTE | IFF_SUBNET);
+	if (ifp->int_flags & IFF_POINTOPOINT &&
+	    (ntohl(((struct sockaddr_in *)&ifp->int_dstaddr)->sin_addr.s_addr) &
+	    ifp->int_netmask) != ifp->int_net)
+		state &= ~RTS_SUBNET;
+	if (ifp->int_flags & IFF_LOOPBACK)
+		state |= RTS_EXTERNAL;
+	rtadd(dst, &ifp->int_addr, ifp->int_metric, state);
+	if (ifp->int_flags & IFF_POINTOPOINT && foundloopback)
+		add_ptopt_localrt(ifp);
+}
+
+/*
+ * Add route to local end of point-to-point using loopback.
+ * If a route to this network is being sent to neighbors on other nets,
+ * mark this route as subnet so we don't have to propagate it too.
+ */
+
+void add_ptopt_localrt(struct interface *ifp)
+{
+	struct rt_entry *rt;
+	struct sockaddr *dst;
+	struct sockaddr_in net;
+	int state;
+
+	state = RTS_INTERFACE | RTS_PASSIVE;
+
+	/* look for route to logical network */
+	memset(&net, 0, sizeof (net));
+	net.sin_family = AF_INET;
+	net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY);
+	dst = (struct sockaddr *)&net;
+	rt = rtfind(dst);
+	if (rt && rt->rt_state & RTS_INTERNAL)
+		state |= RTS_SUBNET;
+
+	dst = &ifp->int_addr;
+	if ((rt = rtfind(dst))!=NULL) {
+		if (rt && rt->rt_state & RTS_INTERFACE)
+			return;
+		rtdelete(rt);
+	}
+	rtadd(dst, &loopaddr, 1, state);
+}
+
+/*
+ * As a concession to the ARPANET we read a list of gateways
+ * from /etc/gateways and add them to our tables.  This file
+ * exists at each ARPANET gateway and indicates a set of ``remote''
+ * gateways (i.e. a gateway which we can't immediately determine
+ * if it's present or not as we can do for those directly connected
+ * at the hardware level).  If a gateway is marked ``passive''
+ * in the file, then we assume it doesn't have a routing process
+ * of our design and simply assume it's always present.  Those
+ * not marked passive, external nor announced are treated as if they
+ * were directly connected -- they're added into the interface list
+ * so we'll send them routing updates.
+ *
+ * PASSIVE ENTRIES AREN'T NEEDED OR USED ON GATEWAYS RUNNING EGP.
+ */
+
+void gwkludge(void)
+{
+	struct sockaddr_in dst, gate;
+	FILE *fp;
+	char *type, *dname, *gname, *qual, buf[BUFSIZ];
+	struct interface *ifp;
+	int metric, n;
+	struct rt_entry route;
+
+	fp = fopen(_PATH_GATEWAYS, "r");
+	if (fp == NULL)
+		return;
+	qual = buf;
+	dname = buf + 64;
+	gname = buf + ((BUFSIZ - 64) / 3);
+	type = buf + (((BUFSIZ - 64) * 2) / 3);
+	memset(&dst, 0, sizeof (dst));
+	memset(&gate, 0, sizeof (gate));
+	memset(&route, 0, sizeof(route));
+	/*
+	 * format:
+	 * {net | host} XX gateway XX metric DD [passive | external | announced]
+	 */
+#define	readentry(fp) \
+	fscanf((fp), "%s %s gateway %s metric %d %s\n", \
+		type, dname, gname, &metric, qual)
+	for (;;) {
+		if ((n = readentry(fp)) == EOF)
+			break;
+		/*
+		 *	Lusertrap. Vendors should ship the line
+		 *
+		 *	CONFIGME CONFIGME gateway CONFIGME metric 1
+		 *
+		 */
+		if (strcmp(type,"CONFIGME")==0)
+		{
+			fprintf(stderr,"Not starting gated. Please configure first.\n");
+			exit(1);
+		}
+		if (!getnetorhostname(type, dname, &dst))
+			continue;
+		if (!gethostnameornumber(gname, &gate))
+			continue;
+		if (metric == 0)			/* XXX */
+			metric = 1;
+		if (strcmp(qual, "passive") == 0) {
+			/*
+			 * Passive entries aren't placed in our tables,
+			 * only the kernel's, so we don't copy all of the
+			 * external routing information within a net.
+			 * Internal machines should use the default
+			 * route to a suitable gateway (like us).
+			 */
+			route.rt_dst = *(struct sockaddr *) &dst;
+			route.rt_router = *(struct sockaddr *) &gate;
+			route.rt_flags = RTF_UP;
+			if (strcmp(type, "host") == 0)
+				route.rt_flags |= RTF_HOST;
+			if (metric)
+				route.rt_flags |= RTF_GATEWAY;
+			(void) rtioctl(ADD, &route.rt_rt);
+			continue;
+		}
+		if (strcmp(qual, "external") == 0) {
+			/*
+			 * Entries marked external are handled
+			 * by other means, e.g. EGP,
+			 * and are placed in our tables only
+			 * to prevent overriding them
+			 * with something else.
+			 */
+			rtadd((struct sockaddr *)&dst,
+			    (struct sockaddr *)&gate, metric,
+			    RTS_EXTERNAL|RTS_PASSIVE);
+			continue;
+		}
+		if (strcmp(qual, "announced") == 0) {
+			/*
+			 * Entries marked "announced" are added
+			 * into our internal tables and advertised,
+			 * but not added to the kernel routing table.
+			 * This allows sort of route "injection" to RIP1
+			 * network for routes through directly reachable
+			 * gateways that arent capable of RIP1 advertising
+			 * themselves.
+			 */
+			rtadd((struct sockaddr *)&dst,
+			    (struct sockaddr *)&gate, metric,
+			    RTS_CHANGED|RTS_PASSIVE|RTS_INTERNAL);
+			continue;
+		}
+		/* assume no duplicate entries */
+		externalinterfaces++;
+		ifp = (struct interface *)malloc(sizeof (*ifp));
+		memset(ifp, 0, sizeof (*ifp));
+		ifp->int_flags = IFF_REMOTE;
+		/* can't identify broadcast capability */
+		ifp->int_net = inet_netof_subnet(dst.sin_addr);
+		if (strcmp(type, "host") == 0) {
+			ifp->int_flags |= IFF_POINTOPOINT;
+			ifp->int_dstaddr = *((struct sockaddr *)&dst);
+		}
+		ifp->int_addr = *((struct sockaddr *)&gate);
+		ifp->int_metric = metric;
+		ifp->int_next = ifnet;
+		ifnet = ifp;
+		addrouteforif(ifp);
+	}
+	fclose(fp);
+}
+
+int getnetorhostname(char *type, char *name, struct sockaddr_in *sin)
+{
+
+	if (strcmp(type, "net") == 0) {
+		struct netent *np = getnetbyname(name);
+		int n;
+
+		if (np == 0)
+			n = inet_network(name);
+		else {
+			if (np->n_addrtype != AF_INET)
+				return (0);
+			n = np->n_net;
+			/*
+			 * getnetbyname returns right-adjusted value.
+			 */
+			if (n < 128)
+				n <<= IN_CLASSA_NSHIFT;
+			else if (n < 65536)
+				n <<= IN_CLASSB_NSHIFT;
+			else
+				n <<= IN_CLASSC_NSHIFT;
+		}
+		sin->sin_family = AF_INET;
+		sin->sin_addr = inet_makeaddr(n, INADDR_ANY);
+		return (1);
+	}
+	if (strcmp(type, "host") == 0)
+		return (gethostnameornumber(name, sin));
+	return (0);
+}
+
+int gethostnameornumber(char *name, struct sockaddr_in *sin)
+{
+	struct hostent *hp;
+
+	if (inet_aton(name, &sin->sin_addr) == 0) {
+		hp = gethostbyname(name);
+		if (hp == 0)
+			return (0);
+		memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
+		sin->sin_family = hp->h_addrtype;
+	} else
+		sin->sin_family = AF_INET;
+	return (1);
+}
Index: tables.c
===================================================================
--- tables.c	(nonexistent)
+++ tables.c	(revision 5)
@@ -0,0 +1,422 @@
+/*
+ * Copyright (c) 1983, 1988, 1993
+ *	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 the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * From: @(#)tables.c	5.17 (Berkeley) 6/1/90
+ * From: @(#)tables.c	8.1 (Berkeley) 6/5/93
+ */
+char tables_rcsid[] = 
+  "$Id: tables.c,v 1.13 2000/12/25 14:41:54 jr Exp $";
+
+
+/*
+ * Routing Table Management Daemon
+ */
+
+#include "defs.h"
+#include <sys/ioctl.h>
+#include <syslog.h>
+#include <errno.h>
+#include <search.h>
+
+#ifndef DEBUG
+#define	DEBUG	0
+#endif
+
+#define FIXLEN(s) { }
+
+static int install = !DEBUG;		/* if 1 call kernel */
+struct rthash nethash[ROUTEHASHSIZ];
+struct rthash hosthash[ROUTEHASHSIZ];
+
+/*
+ * Lookup dst in the tables for an exact match.
+ */
+struct rt_entry *rtlookup(struct sockaddr *dst)
+{
+	register struct rt_entry *rt;
+	register struct rthash *rh;
+	register u_int hash;
+	struct afhash h;
+	int doinghost = 1;
+
+	if (dst->sa_family >= af_max)
+		return (0);
+	(*afswitch[dst->sa_family].af_hash)(dst, &h);
+	hash = h.afh_hosthash;
+	rh = &hosthash[hash & ROUTEHASHMASK];
+again:
+	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+		if (rt->rt_hash != hash)
+			continue;
+		if (equal(&rt->rt_dst, dst))
+			return (rt);
+	}
+	if (doinghost) {
+		doinghost = 0;
+		hash = h.afh_nethash;
+		rh = &nethash[hash & ROUTEHASHMASK];
+		goto again;
+	}
+	return (0);
+}
+
+struct sockaddr wildcard;	/* zero valued cookie for wildcard searches */
+
+/*
+ * Find a route to dst as the kernel would.
+ */
+
+struct rt_entry *rtfind(struct sockaddr *dst)
+{
+	register struct rt_entry *rt;
+	register struct rthash *rh;
+	register u_int hash;
+	struct afhash h;
+	int af = dst->sa_family;
+	int doinghost = 1, (*match)(struct sockaddr *,struct sockaddr *)=NULL;
+
+	if (af >= af_max)
+		return (0);
+	(*afswitch[af].af_hash)(dst, &h);
+	hash = h.afh_hosthash;
+	rh = &hosthash[hash & ROUTEHASHMASK];
+
+again:
+	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+		if (rt->rt_hash != hash)
+			continue;
+		if (doinghost) {
+			if (equal(&rt->rt_dst, dst))
+				return (rt);
+		} else {
+			if (rt->rt_dst.sa_family == af &&
+			    (*match)(&rt->rt_dst, dst))
+				return (rt);
+		}
+	}
+	if (doinghost) {
+		doinghost = 0;
+		hash = h.afh_nethash;
+		rh = &nethash[hash & ROUTEHASHMASK];
+		match = afswitch[af].af_netmatch;
+		goto again;
+	}
+	return (0);
+}
+
+void rtadd(struct sockaddr *dst, struct sockaddr *gate, int metric, int state)
+{
+	struct afhash h;
+	register struct rt_entry *rt;
+	struct rthash *rh;
+	int af = dst->sa_family, flags;
+	u_int hash;
+	char buf1[256], buf2[256];
+
+	if (af >= af_max)
+		return;
+	(*afswitch[af].af_hash)(dst, &h);
+	flags = (*afswitch[af].af_rtflags)(dst);
+	/*
+	 * Subnet flag isn't visible to kernel, move to state.	XXX
+	 */
+	FIXLEN(dst);
+	FIXLEN(gate);
+	if (flags & RTF_SUBNET) {
+		state |= RTS_SUBNET;
+		flags &= ~RTF_SUBNET;
+	}
+	if (flags & RTF_HOST) {
+		hash = h.afh_hosthash;
+		rh = &hosthash[hash & ROUTEHASHMASK];
+	} else {
+		hash = h.afh_nethash;
+		rh = &nethash[hash & ROUTEHASHMASK];
+	}
+	rt = (struct rt_entry *)malloc(sizeof (*rt));
+	if (rt == 0)
+		return;
+	rt->rt_hash = hash;
+	rt->rt_dst = *dst;
+	rt->rt_router = *gate;
+	rt->rt_timer = 0;
+	rt->rt_flags = RTF_UP | flags;
+	rt->rt_state = state | RTS_CHANGED;
+	rt->rt_ifp = if_ifwithdstaddr(&rt->rt_dst);
+	if (rt->rt_ifp == 0)
+		rt->rt_ifp = if_ifwithnet(&rt->rt_router);
+	if ((state & RTS_INTERFACE) == 0)
+		rt->rt_flags |= RTF_GATEWAY;
+	rt->rt_metric = metric;
+	insque((struct qelem *)rt, (struct qelem *)rh);
+	TRACE_ACTION("ADD", rt);
+	/*
+	 * If the ioctl fails because the gateway is unreachable
+	 * from this host, discard the entry.  This should only
+	 * occur because of an incorrect entry in /etc/gateways.
+	 */
+	if ((rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
+	    rtioctl(ADD, &rt->rt_rt) < 0) {
+		if (errno != EEXIST && gate->sa_family < af_max)
+			syslog(LOG_ERR,
+			"adding route to net/host %s through gateway %s: %m\n",
+			   (*afswitch[dst->sa_family].af_format)(dst, buf1,
+							     sizeof(buf1)),
+			   (*afswitch[gate->sa_family].af_format)(gate, buf2,
+							      sizeof(buf2)));
+		perror("ADD ROUTE");
+		if (errno == ENETUNREACH) {
+			TRACE_ACTION("DELETE", rt);
+			remque((struct qelem *)rt);
+			free((char *)rt);
+		}
+	}
+}
+
+void rtchange(struct rt_entry *rt, struct sockaddr *gate, short metric)
+{
+	int add = 0, delete = 0, newgateway = 0;
+	struct rtuentry oldroute;
+
+	FIXLEN(gate);
+	FIXLEN(&(rt->rt_router));
+	FIXLEN(&(rt->rt_dst));
+	if (!equal(&rt->rt_router, gate)) {
+		newgateway++;
+		TRACE_ACTION("CHANGE FROM ", rt);
+	} else if (metric != rt->rt_metric)
+		TRACE_NEWMETRIC(rt, metric);
+	if ((rt->rt_state & RTS_INTERNAL) == 0) {
+		/*
+		 * If changing to different router, we need to add
+		 * new route and delete old one if in the kernel.
+		 * If the router is the same, we need to delete
+		 * the route if has become unreachable, or re-add
+		 * it if it had been unreachable.
+		 */
+		if (newgateway) {
+			add++;
+			if (rt->rt_metric != HOPCNT_INFINITY)
+				delete++;
+		} else if (metric == HOPCNT_INFINITY)
+			delete++;
+		else if (rt->rt_metric == HOPCNT_INFINITY)
+			add++;
+	}
+	/* Linux 1.3.12 and up */
+	if (kernel_version >= 0x01030b) {
+		if (add && delete && rt->rt_metric == metric)
+			delete = 0;
+	} else {
+	/* Linux 1.2.x and 1.3.7 - 1.3.11 */
+		if (add && delete)
+			delete = 0;
+	}
+
+	if (delete)
+		oldroute = rt->rt_rt;
+	if ((rt->rt_state & RTS_INTERFACE) && delete) {
+		rt->rt_state &= ~RTS_INTERFACE;
+		rt->rt_flags |= RTF_GATEWAY;
+		if (metric > rt->rt_metric && delete)
+			syslog(LOG_ERR, "%s route to interface %s (timed out)",
+			    add? "changing" : "deleting",
+			    rt->rt_ifp ? rt->rt_ifp->int_name : "?");
+	}
+	if (add) {
+		rt->rt_router = *gate;
+		rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router);
+		if (rt->rt_ifp == 0)
+			rt->rt_ifp = if_ifwithnet(&rt->rt_router);
+	}
+	rt->rt_metric = metric;
+	rt->rt_state |= RTS_CHANGED;
+	if (newgateway)
+		TRACE_ACTION("CHANGE TO   ", rt);
+	if (add && rtioctl(ADD, &rt->rt_rt) < 0)
+		perror("ADD ROUTE");
+	if (delete && rtioctl(DELETE, &oldroute) < 0)
+		perror("DELETE ROUTE");
+}
+
+void rtdelete(struct rt_entry *rt)
+{
+
+	TRACE_ACTION("DELETE", rt);
+	FIXLEN(&(rt->rt_router));
+	FIXLEN(&(rt->rt_dst));
+	if (rt->rt_metric < HOPCNT_INFINITY) {
+	    if ((rt->rt_state & (RTS_INTERFACE|RTS_INTERNAL)) == RTS_INTERFACE)
+		syslog(LOG_ERR,
+		    "deleting route to interface %s? (timed out?)",
+		    rt->rt_ifp->int_name);
+	    if ((rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
+					    rtioctl(DELETE, &rt->rt_rt) < 0)
+		    perror("rtdelete");
+	}
+	remque((struct qelem *)rt);
+	free((char *)rt);
+}
+
+void rtdeleteall(int sig)
+{
+	register struct rthash *rh;
+	register struct rt_entry *rt;
+	struct rthash *base = hosthash;
+	int doinghost = 1, i;
+
+again:
+	for (i = 0; i < ROUTEHASHSIZ; i++) {
+		rh = &base[i];
+		rt = rh->rt_forw;
+		for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+			if (rt->rt_state & RTS_INTERFACE ||
+			    rt->rt_metric >= HOPCNT_INFINITY)
+				continue;
+			TRACE_ACTION("DELETE", rt);
+			if ((rt->rt_state & (RTS_INTERNAL|RTS_EXTERNAL)) == 0 &&
+			    rtioctl(DELETE, &rt->rt_rt) < 0)
+				perror("rtdeleteall");
+		}
+	}
+	if (doinghost) {
+		doinghost = 0;
+		base = nethash;
+		goto again;
+	}
+	exit(sig);
+}
+
+/*
+ * If we have an interface to the wide, wide world,
+ * add an entry for an Internet default route (wildcard) to the internal
+ * tables and advertise it.  This route is not added to the kernel routes,
+ * but this entry prevents us from listening to other people's defaults
+ * and installing them in the kernel here.
+ */
+
+void rtdefault(void)
+{
+
+	rtadd((struct sockaddr *)&inet_default, 
+		(struct sockaddr *)&inet_default, 1,
+		RTS_CHANGED | RTS_PASSIVE | RTS_INTERNAL);
+}
+
+void rtinit(void)
+{
+	register struct rthash *rh;
+	int i;
+
+	for (i = 0; i < ROUTEHASHSIZ; i++) {
+		rh = &nethash[i];
+		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
+	}
+	for (i = 0; i < ROUTEHASHSIZ; i++) {
+		rh = &hosthash[i];
+		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
+	}
+}
+
+int rtioctl(int action, struct rtuentry *ort)
+{
+	struct rtentry rt;
+	unsigned int netmask;
+	unsigned int dst;
+
+	if (install == 0)
+		return (errno = 0);
+
+#undef rt_flags
+#undef rt_ifp
+#undef rt_metric
+#undef rt_dst
+
+	rt.rt_flags = (ort->rtu_flags & (RTF_UP|RTF_GATEWAY|RTF_HOST));
+	rt.rt_metric = ort->rtu_metric;
+	/*
+	 * SIOCADDRT ioctl in linux kernels v. 2.1.15 and up will no longer
+	 * add direct route to subnet/host through interface, even if the
+	 * specified gateway's IP is the same as IP of that interface (BSDism).
+	 * -- if this is the case, assure that no matter what kernel we use,
+	 * the subnet route to directly attached network is always added
+	 * to KRT as direct one.
+	 */
+	if (rt.rt_flags & RTF_GATEWAY) {
+		rt.rt_dev = NULL;
+		rt.rt_gateway = *(struct sockaddr *)&ort->rtu_router;
+	} else {
+		rt.rt_dev = ort->rtu_ifp->int_name;
+		/*
+		 * We could add a direct route to the KRT this way
+		 * on whatever kernel, but kernels v. 2.1.15 and up
+		 * add such route immediately as soon as the interface
+		 * is labelled with IFF_UP. However, the resulting route
+		 * would be added twice, since kernel distinguishes
+		 * between direct route it added itself and the one
+		 * added explicitly by SIOCADDRT ioctl. So instead,
+		 * we safely exit with "route successfully added" sign, here.
+		 */
+		if (kernel_version >= 0x02010f)
+			return 0;
+	}
+	rt.rt_dst = *(struct sockaddr *)&ort->rtu_dst;
+	dst = ((struct sockaddr_in *)&rt.rt_dst)->sin_addr.s_addr;
+	if (rt.rt_flags & RTF_HOST)
+		netmask = 0xffffffff;
+	else
+		netmask = inet_maskof(dst);
+	((struct sockaddr_in *)&rt.rt_genmask)->sin_family = AF_INET;
+	((struct sockaddr_in *)&rt.rt_genmask)->sin_addr.s_addr = netmask;
+	
+	if (traceactions) {
+		fprintf(ftrace, "rtioctl %s %08lx/%08lx\n",
+			action == ADD ? "ADD" : "DEL",
+			(unsigned long int)ntohl(dst),
+			(unsigned long int)ntohl(netmask));
+		fflush(ftrace);
+	}
+
+	switch (action) {
+
+	case ADD:
+		return (ioctl(sock, SIOCADDRT, (char *)&rt));
+
+	case DELETE:
+		return (ioctl(sock, SIOCDELRT, (char *)&rt));
+
+	default:
+		return (-1);
+	}
+}
Index: timer.c
===================================================================
--- timer.c	(nonexistent)
+++ timer.c	(revision 5)
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 1983, 1988, 1993
+ *	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 the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * From: @(#)timer.c	5.10 (Berkeley) 2/28/91 
+ * From: @(#)timer.c	8.1 (Berkeley) 6/5/93
+ */
+char timer_rcsid[] = 
+  "$Id: timer.c,v 1.8 2000/12/25 14:43:05 jr Exp $";
+
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+
+static int faketime;
+
+/*
+ * Timer routine.  Performs routing information supply
+ * duties and manages timers on routing table entries.
+ * Management of the RTS_CHANGED bit assumes that we broadcast
+ * each time called.
+ */
+
+void timer(int signum)
+{
+	register struct rthash *rh;
+	register struct rt_entry *rt;
+	struct rthash *base = hosthash;
+	int doinghost = 1, timetobroadcast;
+
+	(void)signum;
+
+	(void) gettimeofday(&now, (struct timezone *)NULL);
+	faketime += TIMER_RATE;
+	if (lookforinterfaces && (faketime % CHECK_INTERVAL) == 0)
+		ifinit();
+	timetobroadcast = supplier && (faketime % SUPPLY_INTERVAL) == 0;
+again:
+	for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
+		rt = rh->rt_forw;
+		for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+			/*
+			 * We don't advance time on a routing entry for
+			 * a passive gateway or interface.
+			 */
+			if ((rt->rt_state & (RTS_PASSIVE|RTS_INTERFACE)) == 0)
+				rt->rt_timer += TIMER_RATE;
+			if (rt->rt_timer >= GARBAGE_TIME) {
+				rt = rt->rt_back;
+				rtdelete(rt->rt_forw);
+				continue;
+			}
+			if (rt->rt_timer >= EXPIRE_TIME &&
+			    rt->rt_metric < HOPCNT_INFINITY)
+				rtchange(rt, &rt->rt_router, HOPCNT_INFINITY);
+			rt->rt_state &= ~RTS_CHANGED;
+		}
+	}
+	if (doinghost) {
+		doinghost = 0;
+		base = nethash;
+		goto again;
+	}
+	if (timetobroadcast) {
+		toall(supply, 0, (struct interface *)NULL);
+		lastbcast = now;
+		lastfullupdate = now;
+		needupdate = 0;		/* cancel any pending dynamic update */
+		nextbcast.tv_sec = 0;
+	}
+}
+
+/*
+ * On hangup, let everyone know we're going away.
+ */
+ 
+void hup(int signum)
+{
+	register struct rthash *rh;
+	register struct rt_entry *rt;
+	struct rthash *base = hosthash;
+	int doinghost = 1;
+
+	(void)signum;
+
+	if (supplier) {
+again:
+		for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
+			rt = rh->rt_forw;
+			for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw)
+				rt->rt_metric = HOPCNT_INFINITY;
+		}
+		if (doinghost) {
+			doinghost = 0;
+			base = nethash;
+			goto again;
+		}
+		toall(supply, 0, (struct interface *)NULL);
+	}
+	exit(1);
+}
Index: trace.c
===================================================================
--- trace.c	(nonexistent)
+++ trace.c	(revision 5)
@@ -0,0 +1,471 @@
+/*
+ * Copyright (c) 1983, 1988, 1993
+ *	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 the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * From: @(#)trace.c	5.11 (Berkeley) 2/28/91
+ * From: @(#)trace.c	8.1 (Berkeley) 6/5/93
+ */
+char trace_rcsid[] = 
+  "$Id: trace.c,v 1.16 2000/07/22 23:25:11 dholland Exp $";
+
+
+/*
+ * Routing Table Management Daemon
+ */
+#define	RIPCMDS
+#include "defs.h"
+#include <sys/stat.h>
+/* #include <signal.h> <--- unused? */
+#include <fcntl.h>
+#include <syslog.h>
+#include <errno.h>
+#include "pathnames.h"
+#include <time.h>
+
+#define	NRECORDS	50		/* size of circular trace buffer */
+
+FILE	*ftrace = NULL /*stdout*/;	/* output trace file */
+int traceactions=0;			/* on/off */
+int tracepackets;		/* watch packets as they go by */
+int tracehistory;		/* on/off */
+static int tracecontents;	/* watch packet contents as they go by */
+
+static	struct timeval lastlog;
+static	char *savetracename;
+
+
+static int iftraceinit(struct interface *, struct ifdebug *);
+void dumpif(FILE *, struct interface *);
+void dumptrace(FILE *, char *, struct ifdebug *);
+
+void traceinit(struct interface *ifp)
+{
+
+	if (iftraceinit(ifp, &ifp->int_input) &&
+	    iftraceinit(ifp, &ifp->int_output))
+		return;
+	tracehistory = 0;
+	fprintf(stderr, "traceinit: can't init %s\n", ifp->int_name);
+}
+
+static int iftraceinit(struct interface *ifp, struct ifdebug *ifd)
+{
+	struct iftrace *t;
+
+	ifd->ifd_records =
+	  (struct iftrace *)malloc(NRECORDS * sizeof (struct iftrace));
+	if (ifd->ifd_records == 0)
+		return (0);
+	ifd->ifd_front = ifd->ifd_records;
+	ifd->ifd_count = 0;
+	for (t = ifd->ifd_records; t < ifd->ifd_records + NRECORDS; t++) {
+		t->ift_size = 0;
+		t->ift_packet = 0;
+	}
+	ifd->ifd_if = ifp;
+	return (1);
+}
+
+void traceon(char *file)
+{
+	struct stat stbuf;
+	int fd;
+	const char *logdir = _PATH_LOGDIR;
+
+	if (ftrace != NULL)
+		return;
+
+	/*
+	 * Trace file requests could come from anywhere...
+	 */
+        
+	if (strncmp(file, logdir, strlen(logdir)) || strstr(file, "/../")) {
+		syslog(LOG_ERR, "Cannot log to %s: not under %s\n", 
+		       file, logdir);
+		return;
+	}
+
+	/*
+	 * Also check that the environment is sane.
+	 */
+	if (stat(logdir, &stbuf)<0 || !S_ISDIR(stbuf.st_mode)) {
+		syslog(LOG_ERR, "Configuration problem: %s does not exist "
+		       "or is not a directory", logdir);
+		syslog(LOG_ERR, "Logging disabled");
+		return;
+	}
+
+	if ((stbuf.st_mode & 022)!=0 || stbuf.st_uid!=0) {
+		syslog(LOG_ERR, "Configuration problem: wrong permissions for "
+		       "%s (should be mode 700 and owned by root)",
+		       logdir);
+		syslog(LOG_ERR, "Logging disabled");
+		return;
+	}
+        
+	/*
+	 * 7/22/00 took out O_EXCL on the grounds that since we're
+	 * checking that the file is in the log dir, and the log 
+	 * dir is supposed to be root-only, appending to an
+	 * existing file is not particularly evil.
+	 *
+	 * If Linux ever supports O_NOLINK that should go in here though.
+	 */
+	fd = open(file, O_WRONLY|O_APPEND|O_CREAT|O_NDELAY, 0600);
+	
+	if (fd == -1) {
+		syslog(LOG_ERR, "Cannot log to %s: %s\n",
+		       file, strerror(errno));
+		return;
+	}
+	if (fstat(fd, &stbuf) >= 0 && !S_ISREG(stbuf.st_mode)) {
+		syslog(LOG_ERR, "Cannot log to %s: not a regular file\n",
+		       file);
+		return;
+	}
+       
+	fcntl(fd, F_SETFL, 0);  /* Turn NDELAY off */
+
+	savetracename = file;
+	(void) gettimeofday(&now, (struct timezone *)NULL);
+	ftrace = fdopen(fd, "a");
+	if (ftrace == NULL)
+		return;
+	fflush(stdout);
+	fflush(stderr);
+	dup2(fileno(ftrace), 1);
+	dup2(fileno(ftrace), 2);
+	traceactions = 1;
+	fprintf(ftrace, "Tracing enabled %s\n", ctime(&now.tv_sec));
+}
+
+void traceoff(void)
+{
+	if (!traceactions)
+		return;
+	if (ftrace != NULL) {
+		int fd = open(_PATH_DEVNULL, O_RDWR);
+
+		if (fd<0) {
+			fprintf(ftrace, "Disable tracing: /dev/null: %s\n",
+				strerror(errno));
+			return;
+		}
+
+		fprintf(ftrace, "Tracing disabled %s\n",
+		    ctime(&now.tv_sec));
+		fflush(ftrace);
+		(void) dup2(fd, 1);
+		(void) dup2(fd, 2);
+		(void) close(fd);
+		fclose(ftrace);
+		ftrace = NULL;
+	}
+	traceactions = 0;
+	tracehistory = 0;
+	tracepackets = 0;
+	tracecontents = 0;
+}
+
+void sigtrace(int s)
+{
+
+	if (s == SIGUSR2)
+		traceoff();
+	else if (ftrace == NULL && savetracename)
+		traceon(savetracename);
+	else
+		bumploglevel();
+}
+
+/*
+ * Move to next higher level of tracing when -t option processed or
+ * SIGUSR1 is received.  Successive levels are:
+ *	traceactions
+ *	traceactions + tracepackets
+ *	traceactions + tracehistory (packets and contents after change)
+ *	traceactions + tracepackets + tracecontents
+ */
+
+void bumploglevel(void)
+{
+
+	(void) gettimeofday(&now, NULL);
+	if (traceactions == 0) {
+		traceactions++;
+		if (ftrace)
+			fprintf(ftrace, "Tracing actions started %s\n",
+			    ctime(&now.tv_sec));
+	} else if (tracepackets == 0) {
+		tracepackets++;
+		tracehistory = 0;
+		tracecontents = 0;
+		if (ftrace)
+			fprintf(ftrace, "Tracing packets started %s\n",
+			    ctime(&now.tv_sec));
+	} else if (tracehistory == 0) {
+		tracehistory++;
+		if (ftrace)
+			fprintf(ftrace, "Tracing history started %s\n",
+			    ctime(&now.tv_sec));
+	} else {
+		tracepackets++;
+		tracecontents++;
+		tracehistory = 0;
+		if (ftrace)
+			fprintf(ftrace, "Tracing packet contents started %s\n",
+			    ctime(&now.tv_sec));
+	}
+	if (ftrace)
+		fflush(ftrace);
+}
+
+void trace(struct ifdebug *ifd, struct sockaddr *who, char *p, int len,int m)
+{
+	struct iftrace *t;
+
+	if (ifd->ifd_records == 0)
+		return;
+	t = ifd->ifd_front++;
+	if (ifd->ifd_front >= ifd->ifd_records + NRECORDS)
+		ifd->ifd_front = ifd->ifd_records;
+	if (ifd->ifd_count < NRECORDS)
+		ifd->ifd_count++;
+	if (t->ift_size > 0 && t->ift_size < len && t->ift_packet) {
+		free(t->ift_packet);
+		t->ift_packet = 0;
+	}
+	t->ift_stamp = now;
+	t->ift_who = *who;
+	if (len > 0 && t->ift_packet == 0) {
+		t->ift_packet = malloc(len);
+		if (t->ift_packet == 0)
+			len = 0;
+	}
+	if (len > 0)
+		memcpy(t->ift_packet, p, len);
+	t->ift_size = len;
+	t->ift_metric = m;
+}
+
+void traceaction(FILE *fd, char *action, struct rt_entry *rt)
+{
+	struct sockaddr_in *dst, *gate;
+	static struct bits {
+		int		t_bits;
+		const char	*t_name;
+	} flagbits[] = {
+		{ RTF_UP,	"UP" },
+		{ RTF_GATEWAY,	"GATEWAY" },
+		{ RTF_HOST,	"HOST" },
+		{ 0, 0 }
+	}, statebits[] = {
+		{ RTS_PASSIVE,	"PASSIVE" },
+		{ RTS_REMOTE,	"REMOTE" },
+		{ RTS_INTERFACE,"INTERFACE" },
+		{ RTS_CHANGED,	"CHANGED" },
+		{ RTS_INTERNAL,	"INTERNAL" },
+		{ RTS_EXTERNAL,	"EXTERNAL" },
+		{ RTS_SUBNET,	"SUBNET" },
+		{ 0, 0 }
+	};
+	struct bits *p;
+	int first;
+	char *cp;
+
+	if (fd == NULL)
+		return;
+	if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) {
+		fprintf(fd, "\n%.19s:\n", ctime(&now.tv_sec));
+		lastlog = now;
+	}
+	fprintf(fd, "%s ", action);
+	dst = (struct sockaddr_in *)&rt->rt_dst;
+	gate = (struct sockaddr_in *)&rt->rt_router;
+	fprintf(fd, "dst %s, ", inet_ntoa(dst->sin_addr));
+	fprintf(fd, "router %s, metric %d, flags",
+	     inet_ntoa(gate->sin_addr), rt->rt_metric);
+	cp = " %s";
+	for (first = 1, p = flagbits; p->t_bits > 0; p++) {
+		if ((rt->rt_flags & p->t_bits) == 0)
+			continue;
+		fprintf(fd, cp, p->t_name);
+		if (first) {
+			cp = "|%s";
+			first = 0;
+		}
+	}
+	fprintf(fd, " state");
+	cp = " %s";
+	for (first = 1, p = statebits; p->t_bits > 0; p++) {
+		if ((rt->rt_state & p->t_bits) == 0)
+			continue;
+		fprintf(fd, cp, p->t_name);
+		if (first) {
+			cp = "|%s";
+			first = 0;
+		}
+	}
+	fprintf(fd, " timer %d\n", rt->rt_timer);
+	if (tracehistory && !tracepackets &&
+	    (rt->rt_state & RTS_PASSIVE) == 0 && rt->rt_ifp)
+		dumpif(fd, rt->rt_ifp);
+	fflush(fd);
+	if (ferror(fd))
+		traceoff();
+}
+
+void tracenewmetric(FILE *fd, struct rt_entry *rt, int newmetric)
+{
+	struct sockaddr_in *dst, *gate;
+
+	if (fd == NULL)
+		return;
+	if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) {
+		fprintf(fd, "\n%.19s:\n", ctime(&now.tv_sec));
+		lastlog = now;
+	}
+	dst = (struct sockaddr_in *)&rt->rt_dst;
+	gate = (struct sockaddr_in *)&rt->rt_router;
+	fprintf(fd, "CHANGE metric dst %s, ", inet_ntoa(dst->sin_addr));
+	fprintf(fd, "router %s, from %d to %d\n",
+	     inet_ntoa(gate->sin_addr), rt->rt_metric, newmetric);
+	fflush(fd);
+	if (ferror(fd))
+		traceoff();
+}
+
+void dumpif(FILE *fd, struct interface *ifp)
+{
+	if (ifp->int_input.ifd_count || ifp->int_output.ifd_count) {
+		fprintf(fd, "*** Packet history for interface %s ***\n",
+			ifp->int_name);
+		dumptrace(fd, "from", &ifp->int_input);
+		fprintf(fd, "*** end packet history ***\n");
+	}
+}
+
+void dumptrace(FILE *fd, char *dir, struct ifdebug *ifd)
+{
+	struct iftrace *t;
+	char *cp = !strcmp(dir, "to") ? "Output" : "Input";
+
+	if (ifd->ifd_front == ifd->ifd_records &&
+	    ifd->ifd_front->ift_size == 0) {
+		fprintf(fd, "%s: no packets.\n", cp);
+		fflush(fd);
+		return;
+	}
+	fprintf(fd, "%s trace:\n", cp);
+	t = ifd->ifd_front - ifd->ifd_count;
+	if (t < ifd->ifd_records)
+		t += NRECORDS;
+	for ( ; ifd->ifd_count; ifd->ifd_count--, t++) {
+		if (t >= ifd->ifd_records + NRECORDS)
+			t = ifd->ifd_records;
+		if (t->ift_size == 0)
+			continue;
+		dumppacket(fd, dir, &t->ift_who,
+		    t->ift_packet, t->ift_size, &t->ift_stamp);
+	}
+}
+
+void dumppacket(FILE *fd, char *dir, struct sockaddr *sa, 
+	char *cp, int size, struct timeval *stamp)
+{
+	struct rip *msg = (struct rip *)cp;
+	struct sockaddr_in *who=(struct sockaddr_in *)sa;
+	struct netinfo *n;
+
+	if (fd == NULL)
+		return;
+	if (msg->rip_cmd && msg->rip_cmd < RIPCMD_MAX)
+		fprintf(fd, "%s %s %s.%d %.19s:\n", ripcmds[msg->rip_cmd],
+		    dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port),
+		    ctime(&stamp->tv_sec));
+	else {
+		fprintf(fd, "Bad cmd 0x%x %s %s.%d %.19s\n", msg->rip_cmd,
+		    dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port),
+		    ctime(&stamp->tv_sec));
+		fprintf(fd, "size=%d cp=%p packet=%p\n", size, cp, packet);
+		fflush(fd);
+		return;
+	}
+	if (tracepackets && tracecontents == 0) {
+		fflush(fd);
+		return;
+	}
+	switch (msg->rip_cmd) {
+
+	case RIPCMD_REQUEST:
+	case RIPCMD_RESPONSE:
+		size -= 4 * sizeof (char);
+		n = msg->rip_nets;
+		for (; size > 0; n++, size -= sizeof (struct netinfo)) {
+			if (size < (int)sizeof (struct netinfo)) {
+				fprintf(fd, "(truncated record, len %d)\n",
+				    size);
+				break;
+			}
+			if (sizeof(n->rip_dst.sa_family) > 1)
+			    n->rip_dst.sa_family = ntohs(n->rip_dst.sa_family);
+
+			switch ((int)n->rip_dst.sa_family) {
+
+			case AF_INET:
+				fprintf(fd, "\tdst %s metric %ld\n",
+#define	satosin(sa)	((struct sockaddr_in *)&sa)
+				     inet_ntoa(satosin(n->rip_dst)->sin_addr),
+				     (long int)ntohl(n->rip_metric));
+				break;
+
+			default:
+				fprintf(fd, "\taf %d? metric %ld\n",
+				     n->rip_dst.sa_family,
+				     (long int)ntohl(n->rip_metric));
+				break;
+			}
+		}
+		break;
+
+	case RIPCMD_TRACEON:
+		fprintf(fd, "\tfile=%*s\n", size, msg->rip_tracefile);
+		break;
+
+	case RIPCMD_TRACEOFF:
+		break;
+	}
+	fflush(fd);
+	if (ferror(fd))
+		traceoff();
+}
Index: .
===================================================================
--- .	(nonexistent)
+++ .	(revision 5)

Property changes on: .
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~