xref: /csrg-svn/sbin/routed/routed.c (revision 7212)
16920Ssam #ifndef lint
2*7212Ssam static char sccsid[] = "@(#)routed.c	4.17 82/06/17";
36920Ssam #endif
46920Ssam 
56934Ssam /*
66934Ssam  * Routing Table Management Daemon
76934Ssam  */
86934Ssam #include <sys/types.h>
96920Ssam #include <sys/ioctl.h>
106920Ssam #include <sys/socket.h>
116920Ssam #include <net/in.h>
126920Ssam #include <net/if.h>
136920Ssam #include <errno.h>
146920Ssam #include <stdio.h>
156920Ssam #include <nlist.h>
166920Ssam #include <signal.h>
177029Ssam #include <time.h>
187139Ssam #define	RIPCMDS
196920Ssam #include "rip.h"
206920Ssam #include "router.h"
216920Ssam 
226920Ssam #define	LOOPBACKNET	0177
236920Ssam /* casts to keep lint happy */
246920Ssam #define	insque(q,p)	_insque((caddr_t)q,(caddr_t)p)
256920Ssam #define	remque(q)	_remque((caddr_t)q)
266920Ssam #define equal(a1, a2) \
276920Ssam 	(bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof (struct sockaddr)) == 0)
286929Ssam #define	min(a,b)	((a)>(b)?(b):(a))
296920Ssam 
306920Ssam struct nlist nl[] = {
316920Ssam #define	N_IFNET		0
326920Ssam 	{ "_ifnet" },
336920Ssam 	0,
346920Ssam };
356920Ssam 
367139Ssam struct	sockaddr_in routingaddr = { AF_INET, IPPORT_ROUTESERVER };
377139Ssam struct	sockaddr_in noroutingaddr = { AF_INET, IPPORT_ROUTESERVER+1 };
386920Ssam 
396920Ssam int	s;
407130Swnj int	snoroute;		/* socket with no routing */
416929Ssam int	kmem = -1;
427133Swnj int	supplier = -1;		/* process should supply updates */
436962Ssam int	install = 1;		/* if 1 call kernel */
447145Ssam int	lookforinterfaces = 1;
457145Ssam int	performnlist = 1;
467133Swnj int	timeval = -TIMER_RATE;
476920Ssam int	timer();
486920Ssam int	cleanup();
497133Swnj 
507133Swnj #define tprintf if (trace) printf
516920Ssam int	trace = 0;
527029Ssam FILE	*ftrace;
536920Ssam 
547133Swnj char	packet[MAXPACKETSIZE+1];
557133Swnj struct	rip *msg = (struct rip *)packet;
566920Ssam 
576934Ssam struct in_addr if_makeaddr();
587145Ssam struct interface *if_ifwithaddr(), *if_ifwithnet();
597145Ssam extern char *malloc(), *sys_errlist[];
606922Ssam extern int errno, exit();
617133Swnj char	**argv0;
626920Ssam 
637139Ssam int	sendmsg(), supply();
647133Swnj 
656920Ssam main(argc, argv)
666920Ssam 	int argc;
676920Ssam 	char *argv[];
686920Ssam {
696920Ssam 	int cc;
706920Ssam 	struct sockaddr from;
716920Ssam 
727133Swnj 	argv0 = argv;
737029Ssam #ifndef DEBUG
747029Ssam 	if (fork())
757029Ssam 		exit(0);
767029Ssam 	for (cc = 0; cc < 10; cc++)
777029Ssam 		(void) close(cc);
787029Ssam 	(void) open("/", 0);
797029Ssam 	(void) dup2(0, 1);
807029Ssam 	(void) dup2(0, 2);
817029Ssam 	{ int t = open("/dev/tty", 2);
827029Ssam 	  if (t >= 0) {
837029Ssam 		ioctl(t, TIOCNOTTY, (char *)0);
847029Ssam 		(void) close(t);
857029Ssam 	  }
866920Ssam 	}
877029Ssam #endif
886920Ssam 	if (trace) {
897029Ssam 		ftrace = fopen("/etc/routerlog", "w");
907029Ssam 		dup2(fileno(ftrace), 1);
917029Ssam 		dup2(fileno(ftrace), 2);
926920Ssam 	}
936937Ssam #ifdef vax || pdp11
947139Ssam 	routingaddr.sin_port = htons(routingaddr.sin_port);
957139Ssam 	noroutingaddr.sin_port = htons(noroutingaddr.sin_port);
966920Ssam #endif
976920Ssam again:
987139Ssam 	s = socket(SOCK_DGRAM, 0, &routingaddr, 0);
996920Ssam 	if (s < 0) {
1006920Ssam 		perror("socket");
1016920Ssam 		sleep(30);
1026920Ssam 		goto again;
1036920Ssam 	}
1047130Swnj again2:
1057139Ssam 	snoroute = socket(SOCK_DGRAM, 0, &noroutingaddr, SO_DONTROUTE);
1067130Swnj 	if (snoroute < 0) {
1077130Swnj 		perror("socket");
1087130Swnj 		sleep(30);
1097130Swnj 		goto again2;
1107130Swnj 	}
1116920Ssam 	argv++, argc--;
1127133Swnj 	while (argc > 0 && **argv == '-') {
1137133Swnj 		if (!strcmp(*argv, "-s") == 0) {
1146929Ssam 			supplier = 1;
1157133Swnj 			argv++, argc--;
1167133Swnj 			continue;
1177133Swnj 		}
1187133Swnj 		if (!strcmp(*argv, "-q") == 0) {
1196920Ssam 			supplier = 0;
1207133Swnj 			argv++, argc--;
1217133Swnj 			continue;
1227133Swnj 		}
1237133Swnj 		goto usage;
1246920Ssam 	}
1257133Swnj 	if (argc > 0) {
1267133Swnj usage:
1277145Ssam 		fprintf(stderr, "usage: routed [ -sq ]\n");
1287133Swnj 		exit(1);
1297133Swnj 	}
1307133Swnj 	rtinit();
1317133Swnj 	ifinit();
1327133Swnj 	if (supplier < 0)
1337133Swnj 		supplier = 0;
1347133Swnj 	gwkludge();
1357133Swnj 	msg->rip_cmd = RIPCMD_REQUEST;
1367133Swnj 	msg->rip_nets[0].rip_dst.sa_family = AF_UNSPEC;
1377133Swnj 	msg->rip_nets[0].rip_metric = HOPCNT_INFINITY;
1387133Swnj 	toall(sendmsg);
1396920Ssam 	sigset(SIGALRM, timer);
1406929Ssam 	timer();
1416920Ssam 
1426920Ssam 	for (;;) {
1436920Ssam 		cc = receive(s, &from, packet, sizeof (packet));
1446920Ssam 		if (cc <= 0) {
1456920Ssam 			if (cc < 0 && errno != EINTR)
1466920Ssam 				perror("receive");
1476920Ssam 			continue;
1486920Ssam 		}
1496920Ssam 		sighold(SIGALRM);
1506920Ssam 		rip_input(&from, cc);
1516920Ssam 		sigrelse(SIGALRM);
1526920Ssam 	}
1536920Ssam }
1546920Ssam 
1557133Swnj rtinit()
1566920Ssam {
1576934Ssam 	register struct rthash *rh;
1586920Ssam 
1597133Swnj 	for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
1607133Swnj 		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
1617133Swnj 	for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
1627133Swnj 		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
1636920Ssam }
1646920Ssam 
1657145Ssam struct	interface *ifnet;
1667133Swnj 
1677133Swnj ifinit()
1686920Ssam {
1697145Ssam 	struct interface *ifp;
1707145Ssam 	struct ifnet ifs, *next;
1717145Ssam 	int externalinterfaces = 0;
1726920Ssam 
1737145Ssam 	if (performnlist) {
1747145Ssam 		nlist("/vmunix", nl);
1757145Ssam 		if (nl[N_IFNET].n_value == 0) {
1767145Ssam 			printf("ifnet: not in namelist\n");
1777145Ssam 			goto bad;
1787145Ssam 		}
1797145Ssam 		performnlist = 0;
1806920Ssam 	}
1816920Ssam 	if (kmem < 0) {
1827145Ssam 		kmem = open("/dev/kmem", 0);
1837145Ssam 		if (kmem < 0) {
1847145Ssam 			perror("/dev/kmem");
1857145Ssam 			goto bad;
1867145Ssam 		}
1876920Ssam 	}
1886929Ssam 	if (lseek(kmem, (long)nl[N_IFNET].n_value, 0) == -1 ||
1897133Swnj 	    read(kmem, (char *)&next, sizeof (next)) != sizeof (next)) {
1907133Swnj 		printf("ifnet: error reading kmem\n");
1917133Swnj 		goto bad;
1926929Ssam 	}
1937145Ssam 	lookforinterfaces = 0;
1947133Swnj 	while (next) {
1957133Swnj 		if (lseek(kmem, (long)next, 0) == -1 ||
1967145Ssam 		    read(kmem, (char *)&ifs, sizeof (ifs)) != sizeof (ifs)) {
1977133Swnj 			perror("read");
1987133Swnj 			goto bad;
1996929Ssam 		}
2007145Ssam 		next = ifs.if_next;
2017145Ssam 		if ((ifs.if_flags & IFF_UP) == 0) {
2027145Ssam 			lookforinterfaces = 1;
2037133Swnj 			continue;
2047145Ssam 		}
2057145Ssam 		if (if_ifwithaddr(&ifs.if_addr))
2067133Swnj 			continue;
2077145Ssam 		if (ifs.if_addr.sa_family != AF_INET)
2087145Ssam 			continue;
2097145Ssam 		if (ifs.if_net == LOOPBACKNET)
2107145Ssam 			continue;
2117145Ssam 		ifp = (struct interface *)malloc(sizeof (struct interface));
2127145Ssam 		if (ifp == 0) {
2137145Ssam 			printf("routed: out of memory\n");
2147145Ssam 			break;
2157145Ssam 		}
2167145Ssam 		/*
2177145Ssam 		 * Count the # of directly connected networks
2187145Ssam 		 * and point to point links which aren't looped
2197145Ssam 		 * back to ourself.  This is used below to
2207145Ssam 		 * decide if we should be a routing "supplier".
2217145Ssam 		 */
2227145Ssam 		if ((ifs.if_flags & IFF_POINTOPOINT) == 0 ||
2237145Ssam 		    if_ifwithaddr(&ifs.if_dstaddr) == 0)
2247145Ssam 			externalinterfaces++;
2257145Ssam 		ifp->int_addr = ifs.if_addr;
2267145Ssam 		ifp->int_flags = ifs.if_flags | IFF_INTERFACE;
2277145Ssam 		/* this works because broadaddr overlaps dstaddr */
2287145Ssam 		ifp->int_broadaddr = ifs.if_broadaddr;
2297145Ssam 		ifp->int_net = ifs.if_net;
2307145Ssam 		ifp->int_metric = 0;
2317145Ssam 		ifp->int_next = ifnet;
2326929Ssam 		ifnet = ifp;
2337133Swnj 		addrouteforif(ifp);
2347133Swnj 	}
2357145Ssam 	if (externalinterfaces > 1 && supplier < 0)
2367133Swnj 		supplier = 1;
2377133Swnj 	return;
2387133Swnj bad:
2397133Swnj 	sleep(60);
2407145Ssam 	close(kmem), close(s), close(snoroute);
2417133Swnj 	execv("/etc/routed", argv0);
2427133Swnj 	_exit(0177);
2437133Swnj }
2447130Swnj 
2457133Swnj addrouteforif(ifp)
2467145Ssam 	struct interface *ifp;
2477133Swnj {
2487133Swnj 	struct sockaddr_in net;
2497133Swnj 	struct sockaddr *dst;
2507145Ssam 	int state, metric;
2517133Swnj 
2527145Ssam 	if (ifp->int_flags & IFF_POINTOPOINT)
2537145Ssam 		dst = &ifp->int_dstaddr;
2547133Swnj 	else {
2557133Swnj 		bzero((char *)&net, sizeof (net));
2567133Swnj 		net.sin_family = AF_INET;
2577145Ssam 		net.sin_addr = if_makeaddr(ifp->int_net, INADDR_ANY);
2587133Swnj 		dst = (struct sockaddr *)&net;
2596920Ssam 	}
2607145Ssam 	rtadd(dst, &ifp->int_addr, ifp->int_metric,
2617145Ssam 		ifp->int_flags & (IFF_INTERFACE|IFF_PASSIVE|IFF_REMOTE));
2626920Ssam }
2636920Ssam 
2647133Swnj gwkludge()
2657130Swnj {
2667130Swnj 	struct sockaddr_in dst, gate;
2677130Swnj 	FILE *fp;
2687139Ssam 	char buf[BUFSIZ];
2697145Ssam 	struct interface *ifp;
2707145Ssam 	int metric;
2717130Swnj 
2727130Swnj 	fp = fopen("/etc/gateways", "r");
2737130Swnj 	if (fp == NULL)
2747130Swnj 		return;
2757130Swnj 	bzero((char *)&dst, sizeof (dst));
2767130Swnj 	bzero((char *)&gate, sizeof (gate));
2777145Ssam 	dst.sin_family = gate.sin_family = AF_INET;
2787145Ssam 	/* format: dst XX gateway XX metric DD [passive]\n */
2797145Ssam #define	readentry(fp) \
2807145Ssam 	fscanf((fp), "dst %x gateway %x metric %d %s\n", \
2817145Ssam 	&dst.sin_addr.s_addr, &gate.sin_addr.s_addr, &metric, buf)
2827133Swnj 	for (;;) {
2837145Ssam 		if (readentry(fp) == EOF)
2847133Swnj 			break;
2857145Ssam 		ifp = (struct interface *)malloc(sizeof (*ifp));
2867145Ssam 		bzero((char *)ifp, sizeof (*ifp));
2877145Ssam 		ifp->int_flags = IFF_REMOTE;
2887145Ssam 		/* can't identify broadcast capability */
289*7212Ssam 		ifp->int_net = IN_NETOF(dst.sin_addr);
2907145Ssam 		if ((*afswitch[dst.sin_family].af_checkhost)(&dst)) {
2917145Ssam 			ifp->int_flags |= IFF_POINTOPOINT;
2927145Ssam 			ifp->int_dstaddr = *((struct sockaddr *)&dst);
293*7212Ssam 		}
2947145Ssam 		if (strcmp(buf, "passive") == 0)
2957145Ssam 			ifp->int_flags |= IFF_PASSIVE;
2967145Ssam 		ifp->int_addr = *((struct sockaddr *)&gate);
2977145Ssam 		ifp->int_metric = metric;
2987145Ssam 		ifp->int_next = ifnet;
2997145Ssam 		ifnet = ifp;
3007145Ssam 		addrouteforif(ifp);
3017130Swnj 	}
3027130Swnj 	fclose(fp);
3037130Swnj }
3047130Swnj 
3057133Swnj timer()
3066920Ssam {
3076934Ssam 	register struct rthash *rh;
3086920Ssam 	register struct rt_entry *rt;
3096934Ssam 	struct rthash *base = hosthash;
3107145Ssam 	int doinghost = 1, supplyeverything;
3116920Ssam 
3127133Swnj 	timeval += TIMER_RATE;
3137145Ssam 	if (lookforinterfaces && (timeval % CHECK_INTERVAL) == 0)
3147145Ssam 		ifinit();
3157145Ssam 	supplyeverything = supplier && (timeval % SUPPLY_INTERVAL) == 0;
3167133Swnj 	tprintf(">>> time %d >>>\n", timeval);
3176920Ssam again:
3187133Swnj 	for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
3197133Swnj 		rt = rh->rt_forw;
3207133Swnj 		for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
3217145Ssam 			if (!(rt->rt_state & RTS_PASSIVE))
3227133Swnj 				rt->rt_timer += TIMER_RATE;
3237133Swnj 			if (rt->rt_timer >= EXPIRE_TIME)
3247133Swnj 				rt->rt_metric = HOPCNT_INFINITY;
3257145Ssam 			log("", rt);
3267145Ssam 			if (rt->rt_timer >= GARBAGE_TIME) {
3277133Swnj 				rt = rt->rt_back;
3287133Swnj 				rtdelete(rt->rt_forw);
3297133Swnj 				continue;
3307133Swnj 			}
3317145Ssam 			if (rt->rt_state & RTS_CHANGED) {
3327145Ssam 				rt->rt_state &= ~RTS_CHANGED;
3337145Ssam 				/* don't send extraneous packets */
3347145Ssam 				if (supplyeverything)
3357145Ssam 					continue;
3367133Swnj 				log("broadcast", rt);
3377133Swnj 				msg->rip_cmd = RIPCMD_RESPONSE;
3387133Swnj 				msg->rip_nets[0].rip_dst = rt->rt_dst;
3397133Swnj 				msg->rip_nets[0].rip_metric =
3407133Swnj 				    min(rt->rt_metric+1, HOPCNT_INFINITY);
3417139Ssam 				toall(sendmsg);
3427133Swnj 			}
3437133Swnj 		}
3446920Ssam 	}
3456920Ssam 	if (doinghost) {
3467133Swnj 		doinghost = 0;
3476929Ssam 		base = nethash;
3486920Ssam 		goto again;
3496920Ssam 	}
3507145Ssam 	if (supplyeverything)
3517133Swnj 		toall(supply);
3527133Swnj 	tprintf("<<< time %d <<<\n", timeval);
3537133Swnj 	alarm(TIMER_RATE);
3546920Ssam }
3556920Ssam 
3567133Swnj toall(f)
3577133Swnj 	int (*f)();
3586920Ssam {
3597145Ssam 	register struct interface *ifp;
3606920Ssam 	register struct sockaddr *dst;
3616920Ssam 
3627145Ssam 	for (ifp = ifnet; ifp; ifp = ifp->int_next) {
3637145Ssam 		if (ifp->int_flags & IFF_PASSIVE)
3646920Ssam 			continue;
3657145Ssam 		dst = ifp->int_flags & IFF_BROADCAST ? &ifp->int_broadaddr :
3667145Ssam 		      ifp->int_flags & IFF_POINTOPOINT ? &ifp->int_dstaddr :
3677145Ssam 		      &ifp->int_addr;
3687145Ssam 		(*f)(dst, ifp->int_flags & IFF_INTERFACE);
3696920Ssam 	}
3706920Ssam }
3716920Ssam 
3727139Ssam /*ARGSUSED*/
3737139Ssam sendmsg(dst, dontroute)
3747133Swnj 	struct sockaddr *dst;
3757139Ssam 	int dontroute;
3767133Swnj {
3777133Swnj 	(*afswitch[dst->sa_family].af_output)(s, dst, sizeof (struct rip));
3787133Swnj }
3797133Swnj 
3807139Ssam supply(dst, dontroute)
3817139Ssam 	struct sockaddr *dst;
3827139Ssam 	int dontroute;
3837139Ssam {
3847133Swnj 	register struct rt_entry *rt;
3856920Ssam 	struct netinfo *n = msg->rip_nets;
3866934Ssam 	register struct rthash *rh;
3876934Ssam 	struct rthash *base = hosthash;
3886929Ssam 	int doinghost = 1, size;
3897139Ssam 	int (*output)() = afswitch[dst->sa_family].af_output;
3907139Ssam 	int sto = dontroute ? snoroute : s;
3916920Ssam 
392*7212Ssam 	msg->rip_cmd = RIPCMD_RESPONSE;
3936920Ssam again:
3946920Ssam 	for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
3956920Ssam 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
3966929Ssam 		size = (char *)n - packet;
3976929Ssam 		if (size > MAXPACKETSIZE - sizeof (struct netinfo)) {
3987139Ssam 			(*output)(sto, dst, size);
3996920Ssam 			n = msg->rip_nets;
4006920Ssam 		}
4016920Ssam 		n->rip_dst = rt->rt_dst;
4026929Ssam 		n->rip_metric = min(rt->rt_metric + 1, HOPCNT_INFINITY);
4036929Ssam 		n++;
4046920Ssam 	}
4056920Ssam 	if (doinghost) {
4066920Ssam 		doinghost = 0;
4076920Ssam 		base = nethash;
4086920Ssam 		goto again;
4096920Ssam 	}
4106929Ssam 	if (n != msg->rip_nets)
4117139Ssam 		(*output)(sto, dst, (char *)n - packet);
4126920Ssam }
4136920Ssam 
4146920Ssam /*
4156920Ssam  * Handle an incoming routing packet.
4166920Ssam  */
4176920Ssam rip_input(from, size)
4186920Ssam 	struct sockaddr *from;
4196920Ssam 	int size;
4206920Ssam {
4216920Ssam 	struct rt_entry *rt;
4226920Ssam 	struct netinfo *n;
4237145Ssam 	struct interface *ifp;
4247133Swnj 	time_t t;
4257139Ssam 	int newsize;
4267139Ssam 	struct afswitch *afp;
4276920Ssam 
4287139Ssam 	if (trace) {
4297139Ssam 		if (msg->rip_cmd < RIPCMD_MAX)
4307139Ssam 			printf("%s from %x\n", ripcmds[msg->rip_cmd],
4317139Ssam 			    ((struct sockaddr_in *)from)->sin_addr);
4327139Ssam 		else
4337139Ssam 			printf("%x from %x\n", msg->rip_cmd,
4347139Ssam 			    ((struct sockaddr_in *)from)->sin_addr);
4357139Ssam 	}
4367139Ssam 	if (from->sa_family >= AF_MAX)
4377139Ssam 		return;
4387139Ssam 	afp = &afswitch[from->sa_family];
4396937Ssam 	switch (msg->rip_cmd) {
4406937Ssam 
4417139Ssam 	case RIPCMD_REQUEST:
4427139Ssam 		newsize = 0;
4437139Ssam 		size -= 4 * sizeof (char);
4447139Ssam 		n = msg->rip_nets;
4457139Ssam 		while (size > 0) {
4467139Ssam 			if (size < sizeof (struct netinfo))
4477139Ssam 				break;
4487139Ssam 			size -= sizeof (struct netinfo);
4496920Ssam 
4507139Ssam 			/*
4517139Ssam 			 * A single entry with sa_family == AF_UNSPEC and
4527139Ssam 			 * metric ``infinity'' means ``all routes''.
4537139Ssam 			 */
4547139Ssam 			if (n->rip_dst.sa_family == AF_UNSPEC &&
4557139Ssam 			    n->rip_metric == HOPCNT_INFINITY && size == 0) {
456*7212Ssam 				supply(from, 0);
4577139Ssam 				return;
4587139Ssam 			}
4597139Ssam 			rt = rtlookup(&n->rip_dst);
4607139Ssam 			n->rip_metric = rt == 0 ? HOPCNT_INFINITY :
4617139Ssam 				min(rt->rt_metric+1, HOPCNT_INFINITY);
4627139Ssam 			n++, newsize += sizeof (struct netinfo);
4637139Ssam 		}
4647139Ssam 		if (newsize > 0) {
4657139Ssam 			msg->rip_cmd = RIPCMD_RESPONSE;
4667139Ssam 			newsize += sizeof (int);
4677139Ssam 			(*afp->af_output)(s, from, newsize);
4687139Ssam 		}
4696920Ssam 		return;
4706937Ssam 
4717029Ssam 	case RIPCMD_TRACEON:
4727139Ssam 		if ((*afp->af_portcheck)(from) == 0)
4737029Ssam 			return;
4747133Swnj 		if (trace)
4757133Swnj 			return;
4767133Swnj 		packet[size] = '\0';
4777133Swnj 		ftrace = fopen(msg->rip_tracefile, "a");
4787133Swnj 		if (ftrace == NULL)
4797133Swnj 			return;
4807133Swnj 		(void) dup2(fileno(ftrace), 1);
4817133Swnj 		(void) dup2(fileno(ftrace), 2);
4827133Swnj 		trace = 1;
4837133Swnj 		t = time(0);
4847133Swnj 		printf("*** Tracing turned on at %.24s ***\n", ctime(&t));
4857029Ssam 		return;
4867029Ssam 
4877133Swnj 	case RIPCMD_TRACEOFF:
4887133Swnj 		/* verify message came from a priviledged port */
4897139Ssam 		if ((*afp->af_portcheck)(from) == 0)
4906937Ssam 			return;
4917029Ssam 		if (!trace)
4927029Ssam 			return;
4937029Ssam 		t = time(0);
4947029Ssam 		printf("*** Tracing turned off at %.24s ***\n", ctime(&t));
4957029Ssam 		fflush(stdout), fflush(stderr);
4967029Ssam 		if (ftrace)
4977029Ssam 			fclose(ftrace);
4987029Ssam 		(void) close(1), (void) close(2);
4997029Ssam 		trace = 0;
5007029Ssam 		return;
5017133Swnj 
5027133Swnj 	case RIPCMD_RESPONSE:
5037133Swnj 		/* verify message came from a router */
5047139Ssam 		if ((*afp->af_portmatch)(from) == 0)
5057133Swnj 			return;
5067139Ssam 		(*afp->af_canon)(from);
5077133Swnj 		/* are we talking to ourselves? */
5087133Swnj 		ifp = if_ifwithaddr(from);
5097133Swnj 		if (ifp) {
5107145Ssam 			rt = rtfind(from);
5117145Ssam 			if (rt == 0)
5127133Swnj 				addrouteforif(ifp);
5137145Ssam 			else
5147145Ssam 				rt->rt_timer = 0;
5157133Swnj 			return;
5167133Swnj 		}
5177133Swnj 		size -= 4 * sizeof (char);
5187133Swnj 		n = msg->rip_nets;
5197133Swnj 		for (; size > 0; size -= sizeof (struct netinfo), n++) {
5207133Swnj 			if (size < sizeof (struct netinfo))
5217133Swnj 				break;
5227133Swnj 			if (n->rip_metric >= HOPCNT_INFINITY)
5237133Swnj 				continue;
5247133Swnj 			tprintf("dst %x hc %d...",
5257133Swnj 			    ((struct sockaddr_in *)&n->rip_dst)->sin_addr,
5267133Swnj 			    n->rip_metric);
5277133Swnj 			rt = rtlookup(&n->rip_dst);
5287133Swnj 			if (rt == 0) {
5297133Swnj 				rtadd(&n->rip_dst, from, n->rip_metric, 0);
5307133Swnj 				continue;
5317133Swnj 			}
5327133Swnj 			tprintf("ours: gate %x hc %d timer %d\n",
5337133Swnj 			  ((struct sockaddr_in *)&rt->rt_router)->sin_addr,
5347133Swnj 			  rt->rt_metric, rt->rt_timer);
5357139Ssam 
5367133Swnj 			/*
5377139Ssam 			 * update if from gateway, shorter, or getting
5387139Ssam 			 * stale and equivalent.
5397133Swnj 			 */
5407133Swnj 			if (equal(from, &rt->rt_router) ||
5417133Swnj 			    n->rip_metric < rt->rt_metric ||
5427133Swnj 			    (rt->rt_timer > (EXPIRE_TIME/2) &&
5437133Swnj 			    rt->rt_metric == n->rip_metric)) {
5447133Swnj 				rtchange(rt, from, n->rip_metric);
5457133Swnj 				rt->rt_timer = 0;
5467133Swnj 			}
5477133Swnj 		}
5487133Swnj 		return;
5497029Ssam 	}
5507145Ssam 	tprintf("bad packet, cmd=%x\n", msg->rip_cmd);
5517029Ssam }
5527029Ssam 
5536920Ssam struct rt_entry *
5546920Ssam rtlookup(dst)
5556920Ssam 	struct sockaddr *dst;
5566920Ssam {
5576920Ssam 	register struct rt_entry *rt;
5586934Ssam 	register struct rthash *rh;
5597011Ssam 	register int hash;
5606920Ssam 	struct afhash h;
5617011Ssam 	int doinghost = 1;
5626920Ssam 
5637011Ssam 	if (dst->sa_family >= AF_MAX)
5647011Ssam 		return (0);
5657011Ssam 	(*afswitch[dst->sa_family].af_hash)(dst, &h);
5667011Ssam 	hash = h.afh_hosthash;
5677011Ssam 	rh = &hosthash[hash % ROUTEHASHSIZ];
5687011Ssam again:
5697011Ssam 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
5707145Ssam 		if (rt->rt_hash != hash)
5717011Ssam 			continue;
5727011Ssam 		if (equal(&rt->rt_dst, dst))
5737011Ssam 			return (rt);
5747011Ssam 	}
5757011Ssam 	if (doinghost) {
5767011Ssam 		doinghost = 0;
5777011Ssam 		hash = h.afh_nethash;
5787011Ssam 		rh = &nethash[hash % ROUTEHASHSIZ];
5797011Ssam 		goto again;
5807011Ssam 	}
5817011Ssam 	return (0);
5827011Ssam }
5837011Ssam 
5847011Ssam struct rt_entry *
5857145Ssam rtfind(dst)
5867011Ssam 	struct sockaddr *dst;
5877011Ssam {
5887011Ssam 	register struct rt_entry *rt;
5897011Ssam 	register struct rthash *rh;
5907011Ssam 	register int hash;
5917011Ssam 	struct afhash h;
5927011Ssam 	int af = dst->sa_family;
5937011Ssam 	int doinghost = 1, (*match)();
5947011Ssam 
5956920Ssam 	if (af >= AF_MAX)
5966920Ssam 		return (0);
5976920Ssam 	(*afswitch[af].af_hash)(dst, &h);
5986920Ssam 	hash = h.afh_hosthash;
5996920Ssam 	rh = &hosthash[hash % ROUTEHASHSIZ];
6006920Ssam 
6016920Ssam again:
6026920Ssam 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
6036920Ssam 		if (rt->rt_hash != hash)
6046920Ssam 			continue;
6056920Ssam 		if (doinghost) {
6066920Ssam 			if (equal(&rt->rt_dst, dst))
6076920Ssam 				return (rt);
6086920Ssam 		} else {
6096920Ssam 			if (rt->rt_dst.sa_family == af &&
6106920Ssam 			    (*match)(&rt->rt_dst, dst))
6116920Ssam 				return (rt);
6126920Ssam 		}
6136920Ssam 	}
6146920Ssam 	if (doinghost) {
6156920Ssam 		doinghost = 0;
6166920Ssam 		hash = h.afh_nethash;
6177011Ssam 		rh = &nethash[hash % ROUTEHASHSIZ];
6186920Ssam 		match = afswitch[af].af_netmatch;
6196920Ssam 		goto again;
6206920Ssam 	}
6216920Ssam 	return (0);
6226920Ssam }
6236920Ssam 
6247139Ssam rtadd(dst, gate, metric, state)
6256920Ssam 	struct sockaddr *dst, *gate;
6267139Ssam 	int metric, state;
6276920Ssam {
6286920Ssam 	struct afhash h;
6296920Ssam 	register struct rt_entry *rt;
6306934Ssam 	struct rthash *rh;
6316920Ssam 	int af = dst->sa_family, flags, hash;
6326920Ssam 
6336920Ssam 	if (af >= AF_MAX)
6346920Ssam 		return;
6356920Ssam 	(*afswitch[af].af_hash)(dst, &h);
6366920Ssam 	flags = (*afswitch[af].af_checkhost)(dst) ? RTF_HOST : 0;
6376920Ssam 	if (flags & RTF_HOST) {
6386920Ssam 		hash = h.afh_hosthash;
6396920Ssam 		rh = &hosthash[hash % ROUTEHASHSIZ];
6406920Ssam 	} else {
6416920Ssam 		hash = h.afh_nethash;
6426920Ssam 		rh = &nethash[hash % ROUTEHASHSIZ];
6436920Ssam 	}
6446920Ssam 	rt = (struct rt_entry *)malloc(sizeof (*rt));
6456920Ssam 	if (rt == 0)
6466920Ssam 		return;
6476920Ssam 	rt->rt_hash = hash;
6486920Ssam 	rt->rt_dst = *dst;
6497130Swnj 	rt->rt_router = *gate;
6506920Ssam 	rt->rt_metric = metric;
6516920Ssam 	rt->rt_timer = 0;
6527139Ssam 	rt->rt_flags = RTF_UP | flags;
6537145Ssam 	rt->rt_state = state | RTS_CHANGED;
6547130Swnj 	rt->rt_ifp = if_ifwithnet(&rt->rt_router);
6557130Swnj 	if (metric)
6567130Swnj 		rt->rt_flags |= RTF_GATEWAY;
6576920Ssam 	insque(rt, rh);
6586929Ssam 	log("add", rt);
6597145Ssam 	if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
6607145Ssam 		tprintf("SIOCADDRT: %s\n", sys_errlist[errno]);
6616920Ssam }
6626920Ssam 
6636920Ssam rtchange(rt, gate, metric)
6646920Ssam 	struct rt_entry *rt;
6656920Ssam 	struct sockaddr *gate;
6666920Ssam 	short metric;
6676920Ssam {
6687139Ssam 	int doioctl = 0, metricchanged = 0;
6697145Ssam 	struct rtentry oldroute;
6706920Ssam 
6717145Ssam 	if (!equal(&rt->rt_router, gate))
6727139Ssam 		doioctl++;
6736920Ssam 	if (metric != rt->rt_metric) {
6747139Ssam 		metricchanged++;
6756920Ssam 		rt->rt_metric = metric;
6766920Ssam 	}
6777145Ssam 	if (doioctl || metricchanged) {
6787145Ssam 		log("change", rt);
6797145Ssam 		rt->rt_state |= RTS_CHANGED;
6807145Ssam 	}
6817139Ssam 	if (doioctl) {
6827145Ssam 		oldroute = rt->rt_rt;
6837139Ssam 		rt->rt_router = *gate;
6847145Ssam 		if (install) {
6857145Ssam 			if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
6867145Ssam 				tprintf("SIOCADDRT: %s\n", sys_errlist[errno]);
6877145Ssam 			if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
6887145Ssam 				tprintf("SIOCDELRT: %s\n", sys_errlist[errno]);
6897145Ssam 		}
6907139Ssam 	}
6916920Ssam }
6926920Ssam 
6936920Ssam rtdelete(rt)
6946920Ssam 	struct rt_entry *rt;
6956920Ssam {
6966929Ssam 	log("delete", rt);
6977130Swnj 	if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
6987145Ssam 		tprintf("SIOCDELRT: %s\n", sys_errlist[errno]);
6996920Ssam 	remque(rt);
7006920Ssam 	free((char *)rt);
7016920Ssam }
7026920Ssam 
7036920Ssam log(operation, rt)
7046920Ssam 	char *operation;
7056920Ssam 	struct rt_entry *rt;
7066920Ssam {
7076920Ssam 	struct sockaddr_in *dst, *gate;
7086937Ssam 	static struct bits {
7096920Ssam 		int	t_bits;
7106920Ssam 		char	*t_name;
7116937Ssam 	} flagbits[] = {
7126920Ssam 		{ RTF_UP,	"UP" },
7137130Swnj 		{ RTF_GATEWAY,	"GATEWAY" },
7146920Ssam 		{ RTF_HOST,	"HOST" },
7156920Ssam 		{ 0 }
7166937Ssam 	}, statebits[] = {
7177130Swnj 		{ RTS_PASSIVE,	"PASSIVE" },
7187145Ssam 		{ RTS_REMOTE,	"REMOTE" },
7197145Ssam 		{ RTS_INTERFACE,"INTERFACE" },
7207145Ssam 		{ RTS_CHANGED,	"CHANGED" },
7216937Ssam 		{ 0 }
7226920Ssam 	};
7236937Ssam 	register struct bits *p;
7246920Ssam 	register int first;
7256920Ssam 	char *cp;
7266920Ssam 
7276929Ssam 	if (trace == 0)
7286929Ssam 		return;
7296920Ssam 	printf("%s ", operation);
7306920Ssam 	dst = (struct sockaddr_in *)&rt->rt_dst;
7317130Swnj 	gate = (struct sockaddr_in *)&rt->rt_router;
7327145Ssam 	printf("dst %x, router %x, metric %d, flags", dst->sin_addr,
7337145Ssam 		gate->sin_addr, rt->rt_metric);
7346937Ssam 	cp = " %s";
7356937Ssam 	for (first = 1, p = flagbits; p->t_bits > 0; p++) {
7366920Ssam 		if ((rt->rt_flags & p->t_bits) == 0)
7376920Ssam 			continue;
7386920Ssam 		printf(cp, p->t_name);
7396920Ssam 		if (first) {
7406920Ssam 			cp = "|%s";
7416920Ssam 			first = 0;
7426920Ssam 		}
7436920Ssam 	}
7446937Ssam 	printf(" state");
7456937Ssam 	cp = " %s";
7466937Ssam 	for (first = 1, p = statebits; p->t_bits > 0; p++) {
7476937Ssam 		if ((rt->rt_state & p->t_bits) == 0)
7486937Ssam 			continue;
7496937Ssam 		printf(cp, p->t_name);
7506937Ssam 		if (first) {
7516937Ssam 			cp = "|%s";
7526937Ssam 			first = 0;
7536937Ssam 		}
7546937Ssam 	}
7556920Ssam 	putchar('\n');
7566920Ssam }
7576929Ssam 
7587145Ssam struct interface *
7596929Ssam if_ifwithaddr(addr)
7606929Ssam 	struct sockaddr *addr;
7616929Ssam {
7627145Ssam 	register struct interface *ifp;
7636929Ssam 
7646929Ssam #define	same(a1, a2) \
7656929Ssam 	(bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0)
7667145Ssam 	for (ifp = ifnet; ifp; ifp = ifp->int_next) {
7677145Ssam 		if (ifp->int_flags & IFF_REMOTE)
7686929Ssam 			continue;
7697145Ssam 		if (ifp->int_addr.sa_family != addr->sa_family)
7707145Ssam 			continue;
7717145Ssam 		if (same(&ifp->int_addr, addr))
7726929Ssam 			break;
7737145Ssam 		if ((ifp->int_flags & IFF_BROADCAST) &&
7747145Ssam 		    same(&ifp->int_broadaddr, addr))
7756929Ssam 			break;
7766929Ssam 	}
7776929Ssam 	return (ifp);
7786929Ssam #undef same
7796929Ssam }
7806929Ssam 
7817145Ssam struct interface *
7826929Ssam if_ifwithnet(addr)
7836929Ssam 	register struct sockaddr *addr;
7846929Ssam {
7857145Ssam 	register struct interface *ifp;
7866929Ssam 	register int af = addr->sa_family;
7876929Ssam 	register int (*netmatch)();
7886929Ssam 
7896929Ssam 	if (af >= AF_MAX)
7906929Ssam 		return (0);
7916929Ssam 	netmatch = afswitch[af].af_netmatch;
7927145Ssam 	for (ifp = ifnet; ifp; ifp = ifp->int_next) {
7937145Ssam 		if (ifp->int_flags & IFF_REMOTE)
7946929Ssam 			continue;
7957145Ssam 		if (af != ifp->int_addr.sa_family)
7967145Ssam 			continue;
7977145Ssam 		if ((*netmatch)(addr, &ifp->int_addr))
7986929Ssam 			break;
7996929Ssam 	}
8006929Ssam 	return (ifp);
8016929Ssam }
8026929Ssam 
8036929Ssam struct in_addr
8046929Ssam if_makeaddr(net, host)
8056929Ssam 	int net, host;
8066929Ssam {
8076929Ssam 	u_long addr;
8086929Ssam 
8096929Ssam 	if (net < 128)
8106929Ssam 		addr = (net << 24) | host;
8116929Ssam 	else if (net < 65536)
8126929Ssam 		addr = (net << 16) | host;
8136929Ssam 	else
8146929Ssam 		addr = (net << 8) | host;
8156929Ssam #ifdef vax
8166929Ssam 	addr = htonl(addr);
8176929Ssam #endif
8186929Ssam 	return (*(struct in_addr *)&addr);
8196929Ssam }
820