#!/bin/sh
# this is vxrouted_5.1.1-shar.04 (part 4 of a multipart archive)
# do not concatenate these parts, unpack them in order with /bin/sh
# file vxrouted_5.1.1/startup.c continued
#
touch -am 1231235999 $$.touch >/dev/null 2>&1
if test ! -f 1231235999 && test -f $$.touch; then
  shar_touch=touch
else
  shar_touch=:
  echo 'WARNING: not restoring timestamps'
fi
rm -f 1231235999 $$.touch
#
if test ! -r _sharseq.tmp; then
  echo 'Please unpack part 1 first!'
  exit 1
fi
shar_sequence=`cat _sharseq.tmp`
if test "$shar_sequence" != 4; then
  echo "Please unpack part $shar_sequence next!"
  exit 1
fi
if test ! -f _sharnew.tmp; then
  echo 'x - still skipping vxrouted_5.1.1/startup.c'
else
  echo 'x - continuing file vxrouted_5.1.1/startup.c'
  sed 's/^X//' << 'SHAR_EOF' >> 'vxrouted_5.1.1/startup.c' &&
X
/*
X * Routing Table Management Daemon
X */
#include "defs.h"
#include <ioctl.h>
#include <net/if.h>
/* #include <syslog.h> */
X
/* struct	interface *ifnet; */
/* struct	interface **ifnext = &ifnet; */
struct	ifnet *rd_ifnet;
struct	ifnet **ifnext = &rd_ifnet;
int	lookforinterfaces = 1;
int	externalinterfaces = 0;		/* # of remote and local interfaces */
int	foundloopback;			/* valid flag for loopaddr */
struct	sockaddr loopaddr;		/* our address on loopback */
X
/*
X * Find the network interfaces which have configured themselves.
X * If the interface is present but not yet up (for example an
X * ARPANET IMP), set the lookforinterfaces flag so we'll
X * come back later and look again.
X */
rd_ifinit()
{
X	struct interface ifs, *ifp;
X	int s, n;
X	char buf[BUFSIZ];
X        struct ifconf ifc;
X        struct ifreq ifreq, *ifr;
X        struct sockaddr_in *sin;
X	u_long i;
X
X	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
X		logMsg(" LOG_ERR, socket: %m");
X		close(s);
X                return;
X	}
X        ifc.ifc_len = sizeof (buf);
X        ifc.ifc_buf = buf;
X        if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
X                logMsg(" LOG_ERR, ioctl get interface configuration");
X		close(s);
X                return;
X        }
X        ifr = ifc.ifc_req;
X	lookforinterfaces = 0;
X        for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) {
X		bzero((char *)&ifs, sizeof(ifs));
X		ifs.int_addr = ifr->ifr_addr;
X		ifreq = *ifr;
X                if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
X                        logMsg(" LOG_ERR, %s: ioctl (get interface flags)",
X			    ifr->ifr_name);
X                        continue;
X                }
X		ifs.int_flags = ifreq.ifr_flags | IFF_INTERFACE;
X		if ((ifs.int_flags & IFF_UP) == 0 ||
X		    ifr->ifr_addr.sa_family == AF_UNSPEC) {
X			lookforinterfaces = 1;
X			continue;
X		}
X		/* argh, this'll have to change sometime */
X		if (ifs.int_addr.sa_family != AF_INET)
X			continue;
X                if (ifs.int_flags & IFF_POINTOPOINT) {
X                        if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
X                                logMsg(" LOG_ERR, %s: ioctl (get dstaddr)",
X				    ifr->ifr_name);
X                                continue;
X			}
X			if (ifr->ifr_addr.sa_family == AF_UNSPEC) {
X				lookforinterfaces = 1;
X				continue;
X			}
X			ifs.int_dstaddr = ifreq.ifr_dstaddr;
X		}
X		/*
X		 * already known to us?
X		 * This allows multiple point-to-point links
X		 * to share a source address (possibly with one
X		 * other link), but assumes that there will not be
X		 * multiple links with the same destination address.
X		 */
X		if (ifs.int_flags & IFF_POINTOPOINT) {
X			if (if_ifwithdstaddr(&ifs.int_dstaddr))
X				continue;
X		} else if (if_ifwithaddr(&ifs.int_addr))
X			continue;
X		if (ifs.int_flags & IFF_LOOPBACK) {
X			ifs.int_flags |= IFF_PASSIVE;
X			foundloopback = 1;
X			loopaddr = ifs.int_addr;
X			for (ifp = (struct interface *)rd_ifnet; ifp; ifp = ifp->int_next)
X			    if (ifp->int_flags & IFF_POINTOPOINT)
X				add_ptopt_localrt(ifp);
X		}
X                if (ifs.int_flags & IFF_BROADCAST) {
X                        if (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
X                                logMsg(" LOG_ERR, %s: ioctl (get broadaddr)",
X				    ifr->ifr_name);
X                                continue;
X                        }
#ifndef sun
X			ifs.int_broadaddr = ifreq.ifr_broadaddr;
#else
X			ifs.int_broadaddr = ifreq.ifr_addr;
#endif
X		}
#ifdef SIOCGIFMETRIC
X		if (ioctl(s, SIOCGIFMETRIC, (char *)&ifreq) < 0) {
X			logMsg(" LOG_ERR, %s: ioctl (get metric)",
X			    ifr->ifr_name);
X			ifs.int_metric = 0;
X		} else
X			ifs.int_metric = ifreq.ifr_metric;
#else
X		ifs.int_metric = 0;
#endif
X		/*
X		 * Use a minimum metric of one;
X		 * treat the interface metric (default 0)
X		 * as an increment to the hop count of one.
X		 */
X		ifs.int_metric++;
X		if (ioctl(s, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
X			logMsg(" LOG_ERR, %s: ioctl (get netmask)",
X			    ifr->ifr_name);
X			continue;
X		}
X		sin = (struct sockaddr_in *)&ifreq.ifr_addr;
X		ifs.int_subnetmask = ntohl(sin->sin_addr.s_addr);
X		sin = (struct sockaddr_in *)&ifs.int_addr;
X		i = ntohl(sin->sin_addr.s_addr);
X		if (IN_CLASSA(i))
X			ifs.int_netmask = IN_CLASSA_NET;
X		else if (IN_CLASSB(i))
X			ifs.int_netmask = IN_CLASSB_NET;
X		else
X			ifs.int_netmask = IN_CLASSC_NET;
X		ifs.int_net = i & ifs.int_netmask;
X		ifs.int_subnet = i & ifs.int_subnetmask;
X		if (ifs.int_subnetmask != ifs.int_netmask)
X			ifs.int_flags |= IFF_SUBNET;
X		ifp = (struct interface *)malloc(sizeof (struct interface));
X		if (ifp == 0) {
X			printf("routed: out of memory\n");
X			break;
X		}
X		*ifp = ifs;
X		/*
X		 * Count the # of directly connected networks
X		 * and point to point links which aren't looped
X		 * back to ourself.  This is used below to
X		 * decide if we should be a routing ``supplier''.
X		 */
X		if ((ifs.int_flags & IFF_LOOPBACK) == 0 &&
X		    ((ifs.int_flags & IFF_POINTOPOINT) == 0 ||
X		    if_ifwithaddr(&ifs.int_dstaddr) == 0))
X			externalinterfaces++;
X		/*
X		 * If we have a point-to-point link, we want to act
X		 * as a supplier even if it's our only interface,
X		 * as that's the only way our peer on the other end
X		 * can tell that the link is up.
X		 */
X		if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0)
X			supplier = 1;
X		ifp->int_name = malloc(strlen(ifr->ifr_name) + 1);
X		if (ifp->int_name == 0) {
X			fprintf(stderr, "routed: rd_ifinit: out of memory\n");
X			logMsg(" LOG_ERR, routed: rd_ifinit: out of memory\n");
X			close(s);
X			return;
X		}
X		strcpy(ifp->int_name, ifr->ifr_name);
X		*ifnext = (struct ifnet *)ifp;
X		(struct ifnet *)ifnext = &ifp->int_next;
X		traceinit(ifp);
X		addrouteforif(ifp);
X	}
X	if (externalinterfaces > 1 && supplier < 0)
X		supplier = 1;
X	close(s);
}
X
/*
X * Add route for interface if not currently installed.
X * Create route to other end if a point-to-point link,
X * otherwise a route to this (sub)network.
X * INTERNET SPECIFIC.
X */
addrouteforif(ifp)
X	register struct interface *ifp;
{
X	struct sockaddr_in net;
X	struct sockaddr *dst;
X	int state;
X	register struct rt_entry *rt;
X
X	if (ifp->int_flags & IFF_POINTOPOINT)
X		dst = &ifp->int_dstaddr;
X	else {
X		bzero((char *)&net, sizeof (net));
X		net.sin_family = AF_INET;
X		net.sin_addr = inet_makeaddr(ifp->int_subnet, INADDR_ANY);
X		dst = (struct sockaddr *)&net;
X	}
X	rt = rtfind(dst);
X	if (rt &&
X	    (rt->rt_state & (RTS_INTERFACE | RTS_INTERNAL)) == RTS_INTERFACE)
X		return;
X	if (rt)
X		rtdelete(rt);
X	/*
X	 * If interface on subnetted network,
X	 * install route to network as well.
X	 * This is meant for external viewers.
X	 */
X	if ((ifp->int_flags & (IFF_SUBNET|IFF_POINTOPOINT)) == IFF_SUBNET) {
X		struct in_addr subnet;
X
X		subnet = net.sin_addr;
X		net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY);
X		rt = rtfind(dst);
X		if (rt == 0)
X			rtadd(dst, &ifp->int_addr, ifp->int_metric,
X			    ((ifp->int_flags & (IFF_INTERFACE|IFF_REMOTE)) |
X			    RTS_PASSIVE | RTS_INTERNAL | RTS_SUBNET));
X		else if ((rt->rt_state & (RTS_INTERNAL|RTS_SUBNET)) == 
X		    (RTS_INTERNAL|RTS_SUBNET) &&
X		    ifp->int_metric < rt->rt_metric)
X			rtchange(rt, &rt->rt_router, ifp->int_metric);
X		net.sin_addr = subnet;
X	}
X	if (ifp->int_transitions++ > 0)
X		logMsg(" LOG_ERR, re-installing interface %s", ifp->int_name);
X	state = ifp->int_flags &
X	    (IFF_INTERFACE | IFF_PASSIVE | IFF_REMOTE | IFF_SUBNET);
X	if (ifp->int_flags & IFF_POINTOPOINT &&
X	    (ntohl(((struct sockaddr_in *)&ifp->int_dstaddr)->sin_addr.s_addr) &
X	    ifp->int_netmask) != ifp->int_net)
X		state &= ~RTS_SUBNET;
X	if (ifp->int_flags & IFF_LOOPBACK)
X		state |= RTS_EXTERNAL;
X	rtadd(dst, &ifp->int_addr, ifp->int_metric, state);
X	if (ifp->int_flags & IFF_POINTOPOINT && foundloopback)
X		add_ptopt_localrt(ifp);
}
X
/*
X * Add route to local end of point-to-point using loopback.
X * If a route to this network is being sent to neighbors on other nets,
X * mark this route as subnet so we don't have to propagate it too.
X */
add_ptopt_localrt(ifp)
X	register struct interface *ifp;
{
X	struct rt_entry *rt;
X	struct sockaddr *dst;
X	struct sockaddr_in net;
X	int state;
X
X	state = RTS_INTERFACE | RTS_PASSIVE;
X
X	/* look for route to logical network */
X	bzero((char *)&net, sizeof (net));
X	net.sin_family = AF_INET;
X	net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY);
X	dst = (struct sockaddr *)&net;
X	rt = rtfind(dst);
X	if (rt && rt->rt_state & RTS_INTERNAL)
X		state |= RTS_SUBNET;
X
X	dst = &ifp->int_addr;
X	if (rt = rtfind(dst)) {
X		if (rt && rt->rt_state & RTS_INTERFACE)
X			return;
X		rtdelete(rt);
X	}
X	rtadd(dst, &loopaddr, 1, state);
}
X
/*
X * As a concession to the ARPANET we read a list of gateways
X * from /etc/gateways and add them to our tables.  This file
X * exists at each ARPANET gateway and indicates a set of ``remote''
X * gateways (i.e. a gateway which we can't immediately determine
X * if it's present or not as we can do for those directly connected
X * at the hardware level).  If a gateway is marked ``passive''
X * in the file, then we assume it doesn't have a routing process
X * of our design and simply assume it's always present.  Those
X * not marked passive are treated as if they were directly
X * connected -- they're added into the interface list so we'll
X * send them routing updates.
X *
X * PASSIVE ENTRIES AREN'T NEEDED OR USED ON GATEWAYS RUNNING EGP.
X */
gwkludge()
{
X	struct sockaddr_in dst, gate;
X	FILE *fp;
X	char *type, *dname, *gname, *qual, buf[BUFSIZ];
X	struct interface *ifp;
X	int metric, n;
X	struct rt_entry route;
X
X	return;		/* vxworks has not /etc file system */
X	fp = fopen("/etc/gateways", "r");
X	if (fp == NULL)
X		return;
X	qual = buf;
X	dname = buf + 64;
X	gname = buf + ((BUFSIZ - 64) / 3);
X	type = buf + (((BUFSIZ - 64) * 2) / 3);
X	bzero((char *)&dst, sizeof (dst));
X	bzero((char *)&gate, sizeof (gate));
X	bzero((char *)&route, sizeof(route));
/* format: {net | host} XX gateway XX metric DD [passive | external]\n */
#define	readentry(fp) \
X	fscanf((fp), "%s %s gateway %s metric %d %s\n", \
X		type, dname, gname, &metric, qual)
X	for (;;) {
X		if ((n = readentry(fp)) == EOF)
X			break;
X		if (!getnetorhostname(type, dname, &dst))
X			continue;
X		if (!gethostnameornumber(gname, &gate))
X			continue;
X		if (metric == 0)			/* XXX */
X			metric = 1;
X		if (strcmp(qual, "passive") == 0) {
X			/*
X			 * Passive entries aren't placed in our tables,
X			 * only the kernel's, so we don't copy all of the
X			 * external routing information within a net.
X			 * Internal machines should use the default
X			 * route to a suitable gateway (like us).
X			 */
X			route.rt_dst = *(struct sockaddr *) &dst;
X			route.rt_router = *(struct sockaddr *) &gate;
X			route.rt_flags = RTF_UP;
X			if (strcmp(type, "host") == 0)
X				route.rt_flags |= RTF_HOST;
X			if (metric)
X				route.rt_flags |= RTF_GATEWAY;
X			(void) ioctl(rs, SIOCADDRT, (char *)&route.rt_rt);
X			continue;
X		}
X		if (strcmp(qual, "external") == 0) {
X			/*
X			 * Entries marked external are handled
X			 * by other means, e.g. EGP,
X			 * and are placed in our tables only
X			 * to prevent overriding them
X			 * with something else.
X			 */
X			rtadd(&dst, &gate, metric, RTS_EXTERNAL|RTS_PASSIVE);
X			continue;
X		}
X		/* assume no duplicate entries */
X		externalinterfaces++;
X		ifp = (struct interface *)malloc(sizeof (*ifp));
X		bzero((char *)ifp, sizeof (*ifp));
X		ifp->int_flags = IFF_REMOTE;
X		/* can't identify broadcast capability */
X		ifp->int_net = inet_netof(dst.sin_addr);
X		if (strcmp(type, "host") == 0) {
X			ifp->int_flags |= IFF_POINTOPOINT;
X			ifp->int_dstaddr = *((struct sockaddr *)&dst);
X		}
X		ifp->int_addr = *((struct sockaddr *)&gate);
X		ifp->int_metric = metric;
X		ifp->int_next = (struct interface *)rd_ifnet;
X		rd_ifnet = (struct ifnet *)ifp;
X		addrouteforif(ifp);
X	}
X	fclose(fp);
}
X
getnetorhostname(type, name, sin)
X	char *type, *name;
X	struct sockaddr_in *sin;
{
X
X	if (strcmp(type, "net") == 0) {
/*		struct netent *np = getnetbyname(name); */
X		struct netent *np = 0;
X		int n;
X
X		if (np == 0)
X			n = inet_network(name);
X		else {
X			if (np->n_addrtype != AF_INET)
X				return (0);
X			n = np->n_net;
X			/*
X			 * getnetbyname returns right-adjusted value.
X			 */
X			if (n < 128)
X				n <<= IN_CLASSA_NSHIFT;
X			else if (n < 65536)
X				n <<= IN_CLASSB_NSHIFT;
X			else
X				n <<= IN_CLASSC_NSHIFT;
X		}
X		sin->sin_family = AF_INET;
X		sin->sin_addr = inet_makeaddr(n, INADDR_ANY);
X		return (1);
X	}
X	if (strcmp(type, "host") == 0) {
/*		struct hostent *hp = gethostbyname(name); */
X		struct hostent *hp = 0;
X
X		if (hp == 0)
X			sin->sin_addr.s_addr = inet_addr(name);
X		else {
X			if (hp->h_addrtype != AF_INET)
X				return (0);
X			bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
X		}
X		sin->sin_family = AF_INET;
X		return (1);
X	}
X	return (0);
}
X
gethostnameornumber(name, sin)
X	char *name;
X	struct sockaddr_in *sin;
{
X	struct hostent *hp;
X
/*	hp = gethostbyname(name); */
X	hp = 0;
X
X	if (hp) {
X		bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
X		sin->sin_family = hp->h_addrtype;
X		return (1);
X	}
X	sin->sin_addr.s_addr = inet_addr(name);
X	sin->sin_family = AF_INET;
X	return (sin->sin_addr.s_addr != -1);
}
SHAR_EOF
  echo 'File vxrouted_5.1.1/startup.c is complete' &&
  $shar_touch -am 0201162294 'vxrouted_5.1.1/startup.c' &&
  chmod 0644 'vxrouted_5.1.1/startup.c' ||
  echo 'restore of vxrouted_5.1.1/startup.c failed'
  shar_count="`wc -c < 'vxrouted_5.1.1/startup.c'`"
  test 13884 -eq "$shar_count" ||
    echo "vxrouted_5.1.1/startup.c: original size 13884, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= vxrouted_5.1.1/table.h ==============
if test -f 'vxrouted_5.1.1/table.h' && test X"$1" != X"-c"; then
  echo 'x - skipping vxrouted_5.1.1/table.h (File already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting vxrouted_5.1.1/table.h (Text)'
  sed 's/^X//' << 'SHAR_EOF' > 'vxrouted_5.1.1/table.h' &&
/*
X * Copyright (c) 1983 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley.  The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X *	@(#)table.h	5.6 (Berkeley) 6/18/88
X */
X
/*
X * Routing table management daemon.
X */
X
/*
X * Routing table structure; differs a bit from kernel tables.
X *
X * Note: the union below must agree in the first 4 members
X * so the ioctl's will work.
X */
struct rthash {
X	struct	rt_entry *rt_forw;
X	struct	rt_entry *rt_back;
};
X
struct rt_entry {
X	struct	rt_entry *rt_forw;
X	struct	rt_entry *rt_back;
X	union {
X		struct	rtentry rtu_rt;
X		struct {
X			u_long	rtu_hash;
X			struct	sockaddr rtu_dst;
X			struct	sockaddr rtu_router;
X			short	rtu_flags;
X			short	rtu_state;
X			int	rtu_timer;
X			int	rtu_metric;
X			int	rtu_ifmetric;
X			struct	interface *rtu_ifp;
X		} rtu_entry;
X	} rt_rtu;
};
X
#define	rt_rt		rt_rtu.rtu_rt			/* pass to ioctl */
#define	rt_hash		rt_rtu.rtu_entry.rtu_hash	/* for net or host */
#define	rt_dst		rt_rtu.rtu_entry.rtu_dst	/* match value */
#define	rt_router	rt_rtu.rtu_entry.rtu_router	/* who to forward to */
#define	rt_flags	rt_rtu.rtu_entry.rtu_flags	/* kernel flags */
#define	rt_timer	rt_rtu.rtu_entry.rtu_timer	/* for invalidation */
#define	rt_state	rt_rtu.rtu_entry.rtu_state	/* see below */
#define	rt_metric	rt_rtu.rtu_entry.rtu_metric	/* cost of route */
#define	rt_ifmetric	rt_rtu.rtu_entry.rtu_ifmetric	/* cost of route if */
#define	rt_ifp		rt_rtu.rtu_entry.rtu_ifp	/* interface to take */
X
#define	ROUTEHASHSIZ	32		/* must be a power of 2 */
#define	ROUTEHASHMASK	(ROUTEHASHSIZ - 1)
X
/*
X * "State" of routing table entry.
X */
#define	RTS_CHANGED	0x1		/* route has been altered recently */
#define	RTS_EXTERNAL	0x2		/* extern info, not installed or sent */
#define	RTS_INTERNAL	0x4		/* internal route, not installed */
#define	RTS_PASSIVE	IFF_PASSIVE	/* don't time out route */
#define	RTS_INTERFACE	IFF_INTERFACE	/* route is for network interface */
#define	RTS_REMOTE	IFF_REMOTE	/* route is for ``remote'' entity */
#define	RTS_SUBNET	IFF_SUBNET	/* route is for network subnet */
X
/*
X * Flags are same as kernel, with this addition for af_rtflags:
X */
#define	RTF_SUBNET	0x8000		/* pseudo: route to subnet */
X
struct	rthash nethash[ROUTEHASHSIZ];
struct	rthash hosthash[ROUTEHASHSIZ];
struct	rt_entry *rtlookup();
struct	rt_entry *rtfind();
SHAR_EOF
  $shar_touch -am 0218122989 'vxrouted_5.1.1/table.h' &&
  chmod 0644 'vxrouted_5.1.1/table.h' ||
  echo 'restore of vxrouted_5.1.1/table.h failed'
  shar_count="`wc -c < 'vxrouted_5.1.1/table.h'`"
  test 2987 -eq "$shar_count" ||
    echo "vxrouted_5.1.1/table.h: original size 2987, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= vxrouted_5.1.1/tables.c ==============
if test -f 'vxrouted_5.1.1/tables.c' && test X"$1" != X"-c"; then
  echo 'x - skipping vxrouted_5.1.1/tables.c (File already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting vxrouted_5.1.1/tables.c (Text)'
  sed 's/^X//' << 'SHAR_EOF' > 'vxrouted_5.1.1/tables.c' &&
/*
X * Copyright (c) 1983, 1988 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley.  The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
#ifndef lint
static char sccsid[] = "@(#)tables.c	5.15 (Berkeley) 2/18/89";
#endif /* not lint */
X
/*
X * Routing Table Management Daemon
X */
#include "defs.h"
#include <ioctl.h>
#include <errno.h>
/* #include <sys/syslog.h> */
X
#ifndef DEBUG
#define	DEBUG	0
#endif
X
int	install = !DEBUG;		/* if 1 call kernel */
X
/*
X * Lookup dst in the tables for an exact match.
X */
struct rt_entry *
rtlookup(dst)
X	struct sockaddr *dst;
{
X	register struct rt_entry *rt;
X	register struct rthash *rh;
X	register u_int hash;
X	struct afhash h;
X	int doinghost = 1;
X
X	if (dst->sa_family >= af_max)
X		return (0);
X	(*rd_afswitch[dst->sa_family].af_hash)(dst, &h);
X	hash = h.afh_hosthash;
X	rh = &hosthash[hash & ROUTEHASHMASK];
again:
X	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
X		if (rt->rt_hash != hash)
X			continue;
X		if (equal(&rt->rt_dst, dst))
X			return (rt);
X	}
X	if (doinghost) {
X		doinghost = 0;
X		hash = h.afh_nethash;
X		rh = &nethash[hash & ROUTEHASHMASK];
X		goto again;
X	}
X	return (0);
}
X
struct sockaddr rd_wildcard;	/* zero valued cookie for wildcard searches */
X
/*
X * Find a route to dst as the kernel would.
X */
struct rt_entry *
rtfind(dst)
X	struct sockaddr *dst;
{
X	register struct rt_entry *rt;
X	register struct rthash *rh;
X	register u_int hash;
X	struct afhash h;
X	int af = dst->sa_family;
X	int doinghost = 1, (*match)();
X
X	if (af >= af_max)
X		return (0);
X	(*rd_afswitch[af].af_hash)(dst, &h);
X	hash = h.afh_hosthash;
X	rh = &hosthash[hash & ROUTEHASHMASK];
X
again:
X	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
X		if (rt->rt_hash != hash)
X			continue;
X		if (doinghost) {
X			if (equal(&rt->rt_dst, dst))
X				return (rt);
X		} else {
X			if (rt->rt_dst.sa_family == af &&
X			    (*match)(&rt->rt_dst, dst))
X				return (rt);
X		}
X	}
X	if (doinghost) {
X		doinghost = 0;
X		hash = h.afh_nethash;
X		rh = &nethash[hash & ROUTEHASHMASK];
X		match = rd_afswitch[af].af_netmatch;
X		goto again;
X	}
#ifdef notyet
X	/*
X	 * Check for wildcard gateway, by convention network 0.
X	 */
X	if (dst != &rd_wildcard) {
X		dst = &rd_wildcard, hash = 0;
X		goto again;
X	}
#endif
X	return (0);
}
X
rtadd(dst, gate, metric, state)
X	struct sockaddr *dst, *gate;
X	int metric, state;
{
X	struct afhash h;
X	register struct rt_entry *rt;
X	struct rthash *rh;
X	int af = dst->sa_family, flags;
X	u_int hash;
X
X	if (af >= af_max)
X		return;
X	(*rd_afswitch[af].af_hash)(dst, &h);
X	flags = (*rd_afswitch[af].af_rtflags)(dst);
X	/*
X	 * Subnet flag isn't visible to kernel, move to state.	XXX
X	 */
X	if (flags & RTF_SUBNET) {
X		state |= RTS_SUBNET;
X		flags &= ~RTF_SUBNET;
X	}
X	if (flags & RTF_HOST) {
X		hash = h.afh_hosthash;
X		rh = &hosthash[hash & ROUTEHASHMASK];
X	} else {
X		hash = h.afh_nethash;
X		rh = &nethash[hash & ROUTEHASHMASK];
X	}
X	rt = (struct rt_entry *)malloc(sizeof (*rt));
X	if (rt == 0)
X		return;
X	rt->rt_hash = hash;
X	rt->rt_dst = *dst;
X	rt->rt_router = *gate;
X	rt->rt_timer = 0;
X	rt->rt_flags = RTF_UP | flags;
X	rt->rt_state = state | RTS_CHANGED;
X	rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router);
X	if (rt->rt_ifp == 0)
X		rt->rt_ifp = if_ifwithnet(&rt->rt_router);
X	if ((state & RTS_INTERFACE) == 0)
X		rt->rt_flags |= RTF_GATEWAY;
X	rt->rt_metric = metric;
X	insque(rt, rh);
X	TRACE_ACTION("ADD", rt);
X	/*
X	 * If the ioctl fails because the gateway is unreachable
X	 * from this host, discard the entry.  This should only
X	 * occur because of an incorrect entry in /etc/gateways.
X	 */
X	if (install && (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
X	    ioctl(rs, SIOCADDRT, (char *)&rt->rt_rt) < 0) {
X		if (errno != EEXIST && gate->sa_family < af_max)
X			logMsg(" LOG_ERR, adding route to net/host %s through gateway %s: %m\n",
X			   (*rd_afswitch[dst->sa_family].af_format)(dst),
X			   (*rd_afswitch[gate->sa_family].af_format)(gate));
X		perror("SIOCADDRT");
X		if (errno == ENETUNREACH) {
X			TRACE_ACTION("DELETE", rt);
X			remque(rt);
X			free((char *)rt);
X		}
X	}
}
X
rtchange(rt, gate, metric)
X	struct rt_entry *rt;
X	struct sockaddr *gate;
X	short metric;
{
X	int add = 0, delete = 0, newgateway = 0;
X	struct rtentry oldroute;
X
X	if (!equal(&rt->rt_router, gate)) {
X		newgateway++;
X		TRACE_ACTION("CHANGE FROM ", rt);
X	} else if (metric != rt->rt_metric)
X		TRACE_NEWMETRIC(rt, metric);
X	if ((rt->rt_state & RTS_INTERNAL) == 0) {
X		/*
X		 * If changing to different router, we need to add
X		 * new route and delete old one if in the kernel.
X		 * If the router is the same, we need to delete
X		 * the route if has become unreachable, or re-add
X		 * it if it had been unreachable.
X		 */
X		if (newgateway) {
X			add++;
X			if (rt->rt_metric != HOPCNT_INFINITY)
X				delete++;
X		} else if (metric == HOPCNT_INFINITY)
X			delete++;
X		else if (rt->rt_metric == HOPCNT_INFINITY)
X			add++;
X	}
X	if (delete)
X		oldroute = rt->rt_rt;
X	if ((rt->rt_state & RTS_INTERFACE) && delete) {
X		rt->rt_state &= ~RTS_INTERFACE;
X		rt->rt_flags |= RTF_GATEWAY;
X		if (metric > rt->rt_metric && delete)
X			logMsg(" LOG_ERR, %s route to interface %s (timed out)",
X			    add? "changing" : "deleting",
X			    rt->rt_ifp->int_name);
X	}
X	if (add) {
X		rt->rt_router = *gate;
X		rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router);
X		if (rt->rt_ifp == 0)
X			rt->rt_ifp = if_ifwithnet(&rt->rt_router);
X	}
X	rt->rt_metric = metric;
X	rt->rt_state |= RTS_CHANGED;
X	if (newgateway)
X		TRACE_ACTION("CHANGE TO   ", rt);
X	if (add && install)
X		if (ioctl(rs, SIOCADDRT, (char *)&rt->rt_rt) < 0)
X			perror("SIOCADDRT");
X	if (delete && install)
X		if (ioctl(rs, SIOCDELRT, (char *)&oldroute) < 0)
X			perror("SIOCDELRT");
}
X
rtdelete(rt)
X	struct rt_entry *rt;
{
X
X	TRACE_ACTION("DELETE", rt);
X	if (rt->rt_metric < HOPCNT_INFINITY) {
X	    if ((rt->rt_state & (RTS_INTERFACE|RTS_INTERNAL)) == RTS_INTERFACE)
X		logMsg(" LOG_ERR, deleting route to interface %s? timed out?",
X		    rt->rt_ifp->int_name);
X	    if (install &&
X		(rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
X		ioctl(rs, SIOCDELRT, (char *)&rt->rt_rt))
X		    perror("SIOCDELRT");
X	}
X	remque(rt);
X	free((char *)rt);
}
X
rtdeleteall(sig)
X	int sig;
{
X	register struct rthash *rh;
X	register struct rt_entry *rt;
X	struct rthash *base = hosthash;
X	int doinghost = 1;
X
again:
X	for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
X		rt = rh->rt_forw;
X		for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
X			if (rt->rt_state & RTS_INTERFACE ||
X			    rt->rt_metric >= HOPCNT_INFINITY)
X				continue;
X			TRACE_ACTION("DELETE", rt);
X			if ((rt->rt_state & (RTS_INTERNAL|RTS_EXTERNAL)) == 0 &&
X			    ioctl(rs, SIOCDELRT, (char *)&rt->rt_rt))
X				perror("SIOCDELRT");
X		}
X	}
X	if (doinghost) {
X		doinghost = 0;
X		base = nethash;
X		goto again;
X	}
X	exit(sig);
}
X
/*
X * If we have an interface to the wide, wide world,
X * add an entry for an Internet default route (wildcard) to the internal
X * tables and advertise it.  This route is not added to the kernel routes,
X * but this entry prevents us from listening to other people's defaults
X * and installing them in the kernel here.
X */
rtdefault()
{
X	extern struct sockaddr inet_default;
X
X	rtadd(&inet_default, &inet_default, 1,
X		RTS_CHANGED | RTS_PASSIVE | RTS_INTERNAL);
}
X
rd_rtinit()
{
X	register struct rthash *rh;
X
X	for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
X		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
X	for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
X		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
}
SHAR_EOF
  $shar_touch -am 1116154393 'vxrouted_5.1.1/tables.c' &&
  chmod 0644 'vxrouted_5.1.1/tables.c' ||
  echo 'restore of vxrouted_5.1.1/tables.c failed'
  shar_count="`wc -c < 'vxrouted_5.1.1/tables.c'`"
  test 8120 -eq "$shar_count" ||
    echo "vxrouted_5.1.1/tables.c: original size 8120, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= vxrouted_5.1.1/timer.c ==============
if test -f 'vxrouted_5.1.1/timer.c' && test X"$1" != X"-c"; then
  echo 'x - skipping vxrouted_5.1.1/timer.c (File already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting vxrouted_5.1.1/timer.c (Text)'
  sed 's/^X//' << 'SHAR_EOF' > 'vxrouted_5.1.1/timer.c' &&
/*
X * Copyright (c) 1983, 1988 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley.  The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
#ifndef lint
static char sccsid[] = "@(#)timer.c	5.8 (Berkeley) 2/18/89";
#endif /* not lint */
X
/*
X * Routing Table Management Daemon
X */
#include "defs.h"
X
int	faketime;
X
/*
X * Timer routine.  Performs routing information supply
X * duties and manages timers on routing table entries.
X * Management of the RTS_CHANGED bit assumes that we broadcast
X * each time called.
X */
timer()
{
X	register struct rthash *rh;
X	register struct rt_entry *rt;
X	struct rthash *base = hosthash;
X	int doinghost = 1, timetobroadcast;
X	extern int externalinterfaces;
X
X	(void) gettimeofday(&now, (struct timezone *)NULL);
X	faketime += TIMER_RATE;
X	if (lookforinterfaces && (faketime % CHECK_INTERVAL) == 0)
X		rd_ifinit();
X	timetobroadcast = supplier && (faketime % SUPPLY_INTERVAL) == 0;
again:
X	for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
X		rt = rh->rt_forw;
X		for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
X			/*
X			 * We don't advance time on a routing entry for
X			 * a passive gateway, or any interface if we're
X			 * not acting as supplier.
X			 */
X			if (!(rt->rt_state & RTS_PASSIVE) &&
X			    (supplier || !(rt->rt_state & RTS_INTERFACE)))
X				rt->rt_timer += TIMER_RATE;
X			if (rt->rt_timer >= GARBAGE_TIME) {
X				rt = rt->rt_back;
X				rtdelete(rt->rt_forw);
X				continue;
X			}
X			if (rt->rt_timer >= EXPIRE_TIME &&
X			    rt->rt_metric < HOPCNT_INFINITY)
X				rtchange(rt, &rt->rt_router, HOPCNT_INFINITY);
X			rt->rt_state &= ~RTS_CHANGED;
X		}
X	}
X	if (doinghost) {
X		doinghost = 0;
X		base = nethash;
X		goto again;
X	}
X	if (timetobroadcast) {
X		toall(supply, 0, (struct interface *)NULL);
X		lastbcast = now;
X		lastfullupdate = now;
X		needupdate = 0;		/* cancel any pending dynamic update */
X		nextbcast.tv_sec = 0;
X	}
}
X
/*
X * On hangup, let everyone know we're going away.
X */
hup()
{
X	register struct rthash *rh;
X	register struct rt_entry *rt;
X	struct rthash *base = hosthash;
X	int doinghost = 1;
X
X	if (supplier) {
again:
X		for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
X			rt = rh->rt_forw;
X			for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw)
X				rt->rt_metric = HOPCNT_INFINITY;
X		}
X		if (doinghost) {
X			doinghost = 0;
X			base = nethash;
X			goto again;
X		}
X		toall(supply, 0, (struct interface *)NULL);
X	}
X	exit(1);
}
SHAR_EOF
  $shar_touch -am 1116145593 'vxrouted_5.1.1/timer.c' &&
  chmod 0644 'vxrouted_5.1.1/timer.c' ||
  echo 'restore of vxrouted_5.1.1/timer.c failed'
  shar_count="`wc -c < 'vxrouted_5.1.1/timer.c'`"
  test 3059 -eq "$shar_count" ||
    echo "vxrouted_5.1.1/timer.c: original size 3059, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= vxrouted_5.1.1/trace.c ==============
if test -f 'vxrouted_5.1.1/trace.c' && test X"$1" != X"-c"; then
  echo 'x - skipping vxrouted_5.1.1/trace.c (File already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting vxrouted_5.1.1/trace.c (Text)'
  sed 's/^X//' << 'SHAR_EOF' > 'vxrouted_5.1.1/trace.c' &&
/*
X * Copyright (c) 1983, 1988 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley.  The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
#ifndef lint
static char sccsid[] = "@(#)trace.c	5.8 (Berkeley) 2/18/89";
#endif /* not lint */
X
/*
X * Routing Table Management Daemon
X */
#define	RIPCMDS
#include "defs.h"
/* #include <sys/file.h> */
#include <stat.h>
#include <sigLib.h>
#include <inetLib.h>
X
#define	NRECORDS	50		/* size of circular trace buffer */
#ifdef DEBUG
FILE	*ftrace = stdout;
int	traceactions = 0;
#endif
static	struct timeval lastlog;
static	char *savetracename;
char	intabuf[INET_ADDR_LEN];
X
#define  O_RDWR          2               /* +1 == FREAD|FWRITE */
X
traceinit(ifp)
X	register struct interface *ifp;
{
X
X	if (iftraceinit(ifp, &ifp->int_input) &&
X	    iftraceinit(ifp, &ifp->int_output))
X		return;
X	tracehistory = 0;
X	fprintf(stderr, "traceinit: can't init %s\n", ifp->int_name);
}
X
static
iftraceinit(ifp, ifd)
X	struct interface *ifp;
X	register struct ifdebug *ifd;
{
X	register struct iftrace *t;
X
X	ifd->ifd_records =
X	  (struct iftrace *)malloc(NRECORDS * sizeof (struct iftrace));
X	if (ifd->ifd_records == 0)
X		return (0);
X	ifd->ifd_front = ifd->ifd_records;
X	ifd->ifd_count = 0;
X	for (t = ifd->ifd_records; t < ifd->ifd_records + NRECORDS; t++) {
X		t->ift_size = 0;
X		t->ift_packet = 0;
X	}
X	ifd->ifd_if = ifp;
X	return (1);
}
X
traceon(file)
X	char *file;
{
X	struct stat stbuf;
X
X	if (ftrace != NULL)
X		return;
X	if (stat(file, &stbuf) >= 0 && (stbuf.st_mode & S_IFMT) != S_IFREG)
X		return;
X	savetracename = file;
X	(void) gettimeofday(&now, (struct timezone *)NULL);
X	ftrace = fopen(file, "a");
X	if (ftrace == NULL)
X		return;
/*	dup2(fileno(ftrace), 1); */
/*	dup2(fileno(ftrace), 2); */
X	traceactions = 1;
X	fprintf(ftrace, "Tracing enabled %s\n", ctime((time_t *)&now.tv_sec));
}
X
traceoff()
{
X	if (!traceactions)
X		return;
X	if (ftrace != NULL) {
X		int fd = open("/dev/null", O_RDWR);
X
X		fprintf(ftrace, "Tracing disabled %s\n",
X		    ctime((time_t *)&now.tv_sec));
X		fflush(ftrace);
/*		(void) dup2(fd, 1); */
/*		(void) dup2(fd, 2); */
X		(void) close(fd);
X		fclose(ftrace);
X		ftrace = NULL;
X	}
X	traceactions = 0;
X	tracehistory = 0;
X	tracepackets = 0;
X	tracecontents = 0;
}
X
sigtrace(s)
X	int s;
{
X
X	if (s == SIGUSR2)
X		traceoff();
X	else if (ftrace == NULL && savetracename)
X		traceon(savetracename);
X	else
X		bumploglevel();
}
X
/*
X * Move to next higher level of tracing when -t option processed or
X * SIGUSR1 is received.  Successive levels are:
X *	traceactions
X *	traceactions + tracepackets
X *	traceactions + tracehistory (packets and contents after change)
X *	traceactions + tracepackets + tracecontents
X */
bumploglevel()
{
X
X	(void) gettimeofday(&now, (struct timezone *)NULL);
X	if (traceactions == 0) {
X		traceactions++;
X		if (ftrace)
X			fprintf(ftrace, "Tracing actions started %s\n",
X			    ctime((time_t *)&now.tv_sec));
X	} else if (tracepackets == 0) {
X		tracepackets++;
X		tracehistory = 0;
X		tracecontents = 0;
X		if (ftrace)
X			fprintf(ftrace, "Tracing packets started %s\n",
X			    ctime((time_t *)&now.tv_sec));
X	} else if (tracehistory == 0) {
X		tracehistory++;
X		if (ftrace)
X			fprintf(ftrace, "Tracing history started %s\n",
X			    ctime((time_t *)&now.tv_sec));
X	} else {
X		tracepackets++;
X		tracecontents++;
X		tracehistory = 0;
X		if (ftrace)
X			fprintf(ftrace, "Tracing packet contents started %s\n",
X			    ctime((time_t *)&now.tv_sec));
X	}
X	if (ftrace)
X		fflush(ftrace);
}
X
trace(ifd, who, p, len, m)
X	register struct ifdebug *ifd;
X	struct sockaddr *who;
X	char *p;
X	int len, m;
{
X	register struct iftrace *t;
X
X	if (ifd->ifd_records == 0)
X		return;
X	t = ifd->ifd_front++;
X	if (ifd->ifd_front >= ifd->ifd_records + NRECORDS)
X		ifd->ifd_front = ifd->ifd_records;
X	if (ifd->ifd_count < NRECORDS)
X		ifd->ifd_count++;
X	if (t->ift_size > 0 && t->ift_size < len && t->ift_packet) {
X		free(t->ift_packet);
X		t->ift_packet = 0;
X	}
X	t->ift_stamp = now;
X	t->ift_who = *who;
X	if (len > 0 && t->ift_packet == 0) {
X		t->ift_packet = malloc(len);
X		if (t->ift_packet == 0)
X			len = 0;
X	}
X	if (len > 0)
X		bcopy(p, t->ift_packet, len);
X	t->ift_size = len;
X	t->ift_metric = m;
}
X
traceaction(fd, action, rt)
X	FILE *fd;
X	char *action;
X	struct rt_entry *rt;
{
X	struct sockaddr_in *dst, *gate;
X	static struct bits {
X		int	t_bits;
X		char	*t_name;
X	} flagbits[] = {
X		{ RTF_UP,	"UP" },
X		{ RTF_GATEWAY,	"GATEWAY" },
X		{ RTF_HOST,	"HOST" },
X		{ 0 }
X	}, statebits[] = {
X		{ RTS_PASSIVE,	"PASSIVE" },
X		{ RTS_REMOTE,	"REMOTE" },
X		{ RTS_INTERFACE,"INTERFACE" },
X		{ RTS_CHANGED,	"CHANGED" },
X		{ RTS_INTERNAL,	"INTERNAL" },
X		{ RTS_EXTERNAL,	"EXTERNAL" },
X		{ RTS_SUBNET,	"SUBNET" },
X		{ 0 }
X	};
X	register struct bits *p;
X	register int first;
X	char *cp;
X	struct interface *ifp;
X
X	if (fd == NULL)
X		return;
X	if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) {
X		fprintf(fd, "\n%.19s:\n", ctime((time_t *)&now.tv_sec));
X		lastlog = now;
X	}
X	fprintf(fd, "%s ", action);
X	dst = (struct sockaddr_in *)&rt->rt_dst;
X	gate = (struct sockaddr_in *)&rt->rt_router;
X	inet_ntoa_b(dst->sin_addr,intabuf);
X	fprintf(fd, "dst %s, ", intabuf);
X	inet_ntoa_b(gate->sin_addr,intabuf);
X	fprintf(fd, "router %s, metric %d, flags",
X	     intabuf, rt->rt_metric);
X	cp = " %s";
X	for (first = 1, p = flagbits; p->t_bits > 0; p++) {
X		if ((rt->rt_flags & p->t_bits) == 0)
X			continue;
X		fprintf(fd, cp, p->t_name);
X		if (first) {
X			cp = "|%s";
X			first = 0;
X		}
X	}
X	fprintf(fd, " state");
X	cp = " %s";
X	for (first = 1, p = statebits; p->t_bits > 0; p++) {
X		if ((rt->rt_state & p->t_bits) == 0)
X			continue;
X		fprintf(fd, cp, p->t_name);
X		if (first) {
X			cp = "|%s";
X			first = 0;
X		}
X	}
X	fprintf(fd, " timer %d\n", rt->rt_timer);
X	if (tracehistory && !tracepackets &&
X	    (rt->rt_state & RTS_PASSIVE) == 0 && rt->rt_ifp)
X		dumpif(fd, rt->rt_ifp);
X	fflush(fd);
X	if (ferror(fd))
X		traceoff();
}
X
tracenewmetric(fd, rt, newmetric)
X	FILE *fd;
X	struct rt_entry *rt;
X	int newmetric;
{
X	struct sockaddr_in *dst, *gate;
X
X	if (fd == NULL)
X		return;
X	if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) {
X		fprintf(fd, "\n%.19s:\n", ctime((time_t *)&now.tv_sec));
X		lastlog = now;
X	}
X	dst = (struct sockaddr_in *)&rt->rt_dst;
X	gate = (struct sockaddr_in *)&rt->rt_router;
X	inet_ntoa_b(dst->sin_addr,intabuf);
X	fprintf(fd, "CHANGE metric dst %s, ", intabuf);
X	inet_ntoa_b(gate->sin_addr,intabuf);
X	fprintf(fd, "router %s, from %d to %d\n",
X	     intabuf, rt->rt_metric, newmetric);
X	fflush(fd);
X	if (ferror(fd))
X		traceoff();
}
X
dumpif(fd, ifp)
X	FILE *fd;
X	register struct interface *ifp;
{
X	if (ifp->int_input.ifd_count || ifp->int_output.ifd_count) {
X		fprintf(fd, "*** Packet history for interface %s ***\n",
X			ifp->int_name);
#ifdef notneeded
X		dumptrace(fd, "to", &ifp->int_output);
#endif
X		dumptrace(fd, "from", &ifp->int_input);
X		fprintf(fd, "*** end packet history ***\n");
X	}
}
X
dumptrace(fd, dir, ifd)
X	FILE *fd;
X	char *dir;
X	register struct ifdebug *ifd;
{
X	register struct iftrace *t;
X	char *cp = !strcmp(dir, "to") ? "Output" : "Input";
X
X	if (ifd->ifd_front == ifd->ifd_records &&
X	    ifd->ifd_front->ift_size == 0) {
X		fprintf(fd, "%s: no packets.\n", cp);
X		fflush(fd);
X		return;
X	}
X	fprintf(fd, "%s trace:\n", cp);
X	t = ifd->ifd_front - ifd->ifd_count;
X	if (t < ifd->ifd_records)
X		t += NRECORDS;
X	for ( ; ifd->ifd_count; ifd->ifd_count--, t++) {
X		if (t >= ifd->ifd_records + NRECORDS)
X			t = ifd->ifd_records;
X		if (t->ift_size == 0)
X			continue;
X		dumppacket(fd, dir, &t->ift_who, t->ift_packet, t->ift_size,
X		    &t->ift_stamp);
X	}
}
X
dumppacket(fd, dir, who, cp, size, stamp)
X	FILE *fd;
X	struct sockaddr_in *who;		/* should be sockaddr */
X	char *dir, *cp;
X	register int size;
X	struct timeval *stamp;
{
X	register struct rip *msg = (struct rip *)cp;
X	register struct netinfo *n;
X
X	if (fd == NULL)
SHAR_EOF
  : || echo 'restore of vxrouted_5.1.1/trace.c failed'
fi
echo 'End of archive part 4'
echo 'File vxrouted_5.1.1/trace.c is continued in part 5'
echo 5 > _sharseq.tmp
exit 0
