xref: /csrg-svn/sbin/routed/routed.c (revision 7139)
16920Ssam #ifndef lint
2*7139Ssam static char sccsid[] = "@(#)routed.c	4.15 82/06/09";
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>
18*7139Ssam #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 
36*7139Ssam struct	sockaddr_in routingaddr = { AF_INET, IPPORT_ROUTESERVER };
37*7139Ssam 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 */
447133Swnj int	timeval = -TIMER_RATE;
456920Ssam int	timer();
466920Ssam int	cleanup();
477133Swnj 
487133Swnj #define tprintf if (trace) printf
496920Ssam int	trace = 0;
507029Ssam FILE	*ftrace;
516920Ssam 
527133Swnj char	packet[MAXPACKETSIZE+1];
537133Swnj struct	rip *msg = (struct rip *)packet;
546920Ssam 
556934Ssam struct in_addr if_makeaddr();
566934Ssam struct ifnet *if_ifwithaddr(), *if_ifwithnet();
576920Ssam extern char *malloc();
586922Ssam extern int errno, exit();
597133Swnj char	**argv0;
606920Ssam 
61*7139Ssam int	sendmsg(), supply();
627133Swnj 
636920Ssam main(argc, argv)
646920Ssam 	int argc;
656920Ssam 	char *argv[];
666920Ssam {
676920Ssam 	int cc;
686920Ssam 	struct sockaddr from;
696920Ssam 
707133Swnj 	argv0 = argv;
717029Ssam #ifndef DEBUG
727029Ssam 	if (fork())
737029Ssam 		exit(0);
747029Ssam 	for (cc = 0; cc < 10; cc++)
757029Ssam 		(void) close(cc);
767029Ssam 	(void) open("/", 0);
777029Ssam 	(void) dup2(0, 1);
787029Ssam 	(void) dup2(0, 2);
797029Ssam 	{ int t = open("/dev/tty", 2);
807029Ssam 	  if (t >= 0) {
817029Ssam 		ioctl(t, TIOCNOTTY, (char *)0);
827029Ssam 		(void) close(t);
837029Ssam 	  }
846920Ssam 	}
857029Ssam #endif
866920Ssam 	if (trace) {
877029Ssam 		ftrace = fopen("/etc/routerlog", "w");
887029Ssam 		dup2(fileno(ftrace), 1);
897029Ssam 		dup2(fileno(ftrace), 2);
906920Ssam 	}
916937Ssam #ifdef vax || pdp11
92*7139Ssam 	routingaddr.sin_port = htons(routingaddr.sin_port);
93*7139Ssam 	noroutingaddr.sin_port = htons(noroutingaddr.sin_port);
946920Ssam #endif
956920Ssam again:
96*7139Ssam 	s = socket(SOCK_DGRAM, 0, &routingaddr, 0);
976920Ssam 	if (s < 0) {
986920Ssam 		perror("socket");
996920Ssam 		sleep(30);
1006920Ssam 		goto again;
1016920Ssam 	}
1027130Swnj again2:
103*7139Ssam 	snoroute = socket(SOCK_DGRAM, 0, &noroutingaddr, SO_DONTROUTE);
1047130Swnj 	if (snoroute < 0) {
1057130Swnj 		perror("socket");
1067130Swnj 		sleep(30);
1077130Swnj 		goto again2;
1087130Swnj 	}
1096920Ssam 	argv++, argc--;
1107133Swnj 	while (argc > 0 && **argv == '-') {
1117133Swnj 		if (!strcmp(*argv, "-s") == 0) {
1126929Ssam 			supplier = 1;
1137133Swnj 			argv++, argc--;
1147133Swnj 			continue;
1157133Swnj 		}
1167133Swnj 		if (!strcmp(*argv, "-q") == 0) {
1176920Ssam 			supplier = 0;
1187133Swnj 			argv++, argc--;
1197133Swnj 			continue;
1207133Swnj 		}
1217133Swnj 		goto usage;
1226920Ssam 	}
1237133Swnj 	if (argc > 0) {
1247133Swnj usage:
1257133Swnj 		fprintf(stderr, "usage: routed [ -s ]\n");
1267133Swnj 		exit(1);
1277133Swnj 	}
1287133Swnj 	rtinit();
1297133Swnj 	ifinit();
1307133Swnj 	if (supplier < 0)
1317133Swnj 		supplier = 0;
1327133Swnj 	gwkludge();
1337133Swnj 	msg->rip_cmd = RIPCMD_REQUEST;
1347133Swnj 	msg->rip_nets[0].rip_dst.sa_family = AF_UNSPEC;
1357133Swnj 	msg->rip_nets[0].rip_metric = HOPCNT_INFINITY;
1367133Swnj 	toall(sendmsg);
1376920Ssam 	sigset(SIGALRM, timer);
1386929Ssam 	timer();
1396920Ssam 
1406920Ssam 	for (;;) {
1416920Ssam 		cc = receive(s, &from, packet, sizeof (packet));
1426920Ssam 		if (cc <= 0) {
1436920Ssam 			if (cc < 0 && errno != EINTR)
1446920Ssam 				perror("receive");
1456920Ssam 			continue;
1466920Ssam 		}
1476920Ssam 		sighold(SIGALRM);
1486920Ssam 		rip_input(&from, cc);
1496920Ssam 		sigrelse(SIGALRM);
1506920Ssam 	}
1516920Ssam }
1526920Ssam 
1537133Swnj rtinit()
1546920Ssam {
1556934Ssam 	register struct rthash *rh;
1566920Ssam 
1577133Swnj 	for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
1587133Swnj 		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
1597133Swnj 	for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
1607133Swnj 		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
1616920Ssam }
1626920Ssam 
1636934Ssam struct	ifnet *ifnet;
1647133Swnj 
1657133Swnj ifinit()
1666920Ssam {
1677133Swnj 	struct ifnet *ifp, *next;
1687133Swnj 	int uniquemultihostinterfaces = 0;
1696920Ssam 
1707133Swnj 	nlist("/vmunix", nl);
1717133Swnj 	if (nl[N_IFNET].n_value == 0) {
1727133Swnj 		printf("ifnet: not in namelist\n");
1737133Swnj 		goto bad;
1746920Ssam 	}
1757133Swnj 	kmem = open("/dev/kmem", 0);
1766920Ssam 	if (kmem < 0) {
1777133Swnj 		perror("/dev/kmem");
1787133Swnj 		goto bad;
1796920Ssam 	}
1806929Ssam 	if (lseek(kmem, (long)nl[N_IFNET].n_value, 0) == -1 ||
1817133Swnj 	    read(kmem, (char *)&next, sizeof (next)) != sizeof (next)) {
1827133Swnj 		printf("ifnet: error reading kmem\n");
1837133Swnj 		goto bad;
1846929Ssam 	}
1857133Swnj 	while (next) {
1867133Swnj 		ifp = (struct ifnet *)malloc(sizeof (struct ifnet));
1877133Swnj 		if (ifp == 0) {
1887133Swnj 			printf("routed: out of memory\n");
1896920Ssam 			break;
1906920Ssam 		}
1917133Swnj 		if (lseek(kmem, (long)next, 0) == -1 ||
1927133Swnj 		    read(kmem, (char *)ifp, sizeof (*ifp)) != sizeof (*ifp)) {
1937133Swnj 			perror("read");
1947133Swnj 			goto bad;
1956929Ssam 		}
1967133Swnj 		next = ifp->if_next;
1976929Ssam 		if (ifp->if_addr.sa_family != AF_INET)
1987133Swnj 			continue;
1996920Ssam 		if (ifp->if_net == LOOPBACKNET)
2007133Swnj 			continue;
2016929Ssam 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0 ||
2026929Ssam 		    if_ifwithaddr(&ifp->if_dstaddr) == 0)
2037133Swnj 			uniquemultihostinterfaces++;
2046929Ssam 		ifp->if_next = ifnet;
2056929Ssam 		ifnet = ifp;
2067133Swnj 		addrouteforif(ifp);
2077133Swnj 	}
2087133Swnj 	if (uniquemultihostinterfaces > 1 && supplier < 0)
2097133Swnj 		supplier = 1;
2107133Swnj 	return;
2117133Swnj bad:
2127133Swnj 	sleep(60);
2137133Swnj 	execv("/etc/routed", argv0);
2147133Swnj 	_exit(0177);
2157133Swnj }
2167130Swnj 
2177133Swnj addrouteforif(ifp)
2187133Swnj 	struct ifnet *ifp;
2197133Swnj {
2207133Swnj 	struct sockaddr_in net;
2217133Swnj 	struct sockaddr *dst;
2227133Swnj 
2237133Swnj 	if (ifp->if_flags & IFF_POINTOPOINT)
2247133Swnj 		dst = &ifp->if_dstaddr;
2257133Swnj 	else {
2267133Swnj 		bzero((char *)&net, sizeof (net));
2277133Swnj 		net.sin_family = AF_INET;
2287133Swnj 		net.sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
2297133Swnj 		dst = (struct sockaddr *)&net;
2306920Ssam 	}
231*7139Ssam 	rtadd(dst, &ifp->if_addr, 0, RTS_DONTDELETE|RTS_DONTROUTE);
2326920Ssam }
2336920Ssam 
2347133Swnj gwkludge()
2357130Swnj {
2367130Swnj 	struct sockaddr_in dst, gate;
2377130Swnj 	FILE *fp;
238*7139Ssam 	char buf[BUFSIZ];
2397130Swnj 
2407130Swnj 	fp = fopen("/etc/gateways", "r");
2417130Swnj 	if (fp == NULL)
2427130Swnj 		return;
2437130Swnj 	bzero((char *)&dst, sizeof (dst));
2447130Swnj 	bzero((char *)&gate, sizeof (gate));
2457130Swnj 	dst.sin_family = AF_INET;
2467130Swnj 	gate.sin_family = AF_INET;
2477133Swnj 	for (;;) {
248*7139Ssam 		buf[0] = '\0';
249*7139Ssam 		/* format is: dst XX gateway XX [passive]\n */
250*7139Ssam 		if (fscanf(fp, "dst %x gateway %x %s\n", &dst.sin_addr.s_addr,
251*7139Ssam 		   &gate.sin_addr.s_addr, buf) == EOF)
2527133Swnj 			break;
2537133Swnj 		rtadd((struct sockaddr *)&dst, (struct sockaddr *)&gate, 1,
254*7139Ssam 		   strcmp(buf, "passive") == 0 ? RTS_PASSIVE : RTS_DONTDELETE);
2557130Swnj 	}
2567130Swnj 	fclose(fp);
2577130Swnj }
2587130Swnj 
2597133Swnj timer()
2606920Ssam {
2616934Ssam 	register struct rthash *rh;
2626920Ssam 	register struct rt_entry *rt;
2636934Ssam 	struct rthash *base = hosthash;
2647133Swnj 	int doinghost = 1, state;
2656920Ssam 
2667133Swnj 	timeval += TIMER_RATE;
2677133Swnj 	tprintf(">>> time %d >>>\n", timeval);
2686920Ssam again:
2697133Swnj 	for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
2707133Swnj 		rt = rh->rt_forw;
2717133Swnj 		for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
272*7139Ssam 			if (!(rt->rt_state & RTS_PASSIVE)) {
2737133Swnj 				rt->rt_timer += TIMER_RATE;
274*7139Ssam 				if (rt->rt_timer > 9999)
275*7139Ssam 					rt->rt_timer = 9999;
276*7139Ssam 			}
2777133Swnj 			log("", rt);
278*7139Ssam 			if (rt->rt_state & RTS_HIDDEN)
279*7139Ssam 				continue;
2807133Swnj 			if (rt->rt_timer >= EXPIRE_TIME)
2817133Swnj 				rt->rt_metric = HOPCNT_INFINITY;
2827133Swnj 			if ((rt->rt_state & RTS_DELRT) ||
2837133Swnj 			    rt->rt_timer >= GARBAGE_TIME) {
2847133Swnj 				rt = rt->rt_back;
2857133Swnj 				rtdelete(rt->rt_forw);
2867133Swnj 				continue;
2877133Swnj 			}
2887133Swnj 			state = rt->rt_state;
2897133Swnj 			if (rt->rt_state & RTS_ADDRT) {
2907133Swnj 				if (ioctl(s, SIOCADDRT,(char *)&rt->rt_rt) < 0)
2917133Swnj 					perror("SIOCADDRT");
2927133Swnj 				rt->rt_state &= ~RTS_ADDRT;
2937133Swnj 			}
2947133Swnj 			if (rt->rt_state & RTS_CHGRT) {
2957133Swnj 				struct rtentry oldroute;
2967133Swnj 
2977133Swnj 				oldroute = rt->rt_rt;
298*7139Ssam 				oldroute.rt_gateway = rt->rt_oldrouter;
299*7139Ssam 				if (install &&
300*7139Ssam 				    ioctl(s, SIOCADDRT,(char *)&rt->rt_rt) < 0)
3017133Swnj 					perror("SIOCADDRT");
302*7139Ssam 				if (install &&
303*7139Ssam 				    ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
3047133Swnj 					perror("SIOCDELRT");
3057133Swnj 				rt->rt_state &= ~RTS_CHGRT;
3067133Swnj 			}
3077133Swnj 			if (supplier && (state & (RTS_CHGRT|RTS_ADDRT))) {
3087133Swnj 				log("broadcast", rt);
3097133Swnj 				msg->rip_cmd = RIPCMD_RESPONSE;
3107133Swnj 				msg->rip_nets[0].rip_dst = rt->rt_dst;
3117133Swnj 				msg->rip_nets[0].rip_metric =
3127133Swnj 				    min(rt->rt_metric+1, HOPCNT_INFINITY);
313*7139Ssam 				toall(sendmsg);
3147133Swnj 			}
3157133Swnj 		}
3166920Ssam 	}
3176920Ssam 	if (doinghost) {
3187133Swnj 		doinghost = 0;
3196929Ssam 		base = nethash;
3206920Ssam 		goto again;
3216920Ssam 	}
3227133Swnj 	if (supplier && (timeval % SUPPLY_INTERVAL) == 0)
3237133Swnj 		toall(supply);
3247133Swnj 	tprintf("<<< time %d <<<\n", timeval);
3257133Swnj 	alarm(TIMER_RATE);
3266920Ssam }
3276920Ssam 
3287133Swnj toall(f)
3297133Swnj 	int (*f)();
3306920Ssam {
3317133Swnj 	register struct rthash *rh;
3326920Ssam 	register struct rt_entry *rt;
3336920Ssam 	register struct sockaddr *dst;
3346934Ssam 	struct rthash *base = hosthash;
3356920Ssam 	int doinghost = 1;
3366920Ssam 
3376920Ssam again:
3386920Ssam 	for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
3396920Ssam 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
340*7139Ssam 		if ((rt->rt_state & RTS_PASSIVE) || rt->rt_metric > 0)
3416920Ssam 			continue;
3426920Ssam 		if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST))
3436920Ssam 			dst = &rt->rt_ifp->if_broadaddr;
3446920Ssam 		else
3457130Swnj 			dst = &rt->rt_router;
346*7139Ssam 		(*f)(dst, rt->rt_state & RTS_DONTROUTE);
3476920Ssam 	}
3486920Ssam 	if (doinghost) {
3496920Ssam 		base = nethash;
3506920Ssam 		doinghost = 0;
3516920Ssam 		goto again;
3526920Ssam 	}
3536920Ssam }
3546920Ssam 
355*7139Ssam /*ARGSUSED*/
356*7139Ssam sendmsg(dst, dontroute)
3577133Swnj 	struct sockaddr *dst;
358*7139Ssam 	int dontroute;
3597133Swnj {
3607133Swnj 	(*afswitch[dst->sa_family].af_output)(s, dst, sizeof (struct rip));
3617133Swnj }
3627133Swnj 
363*7139Ssam supply(dst, dontroute)
364*7139Ssam 	struct sockaddr *dst;
365*7139Ssam 	int dontroute;
366*7139Ssam {
3677133Swnj 	register struct rt_entry *rt;
3686920Ssam 	struct netinfo *n = msg->rip_nets;
3696934Ssam 	register struct rthash *rh;
3706934Ssam 	struct rthash *base = hosthash;
3716929Ssam 	int doinghost = 1, size;
372*7139Ssam 	int (*output)() = afswitch[dst->sa_family].af_output;
373*7139Ssam 	int sto = dontroute ? snoroute : s;
3746920Ssam 
3756920Ssam again:
3766920Ssam 	for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
3776920Ssam 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
378*7139Ssam 		if (rt->rt_state & RTS_HIDDEN)
379*7139Ssam 			continue;
3806929Ssam 		size = (char *)n - packet;
3816929Ssam 		if (size > MAXPACKETSIZE - sizeof (struct netinfo)) {
382*7139Ssam 			(*output)(sto, dst, size);
3836920Ssam 			n = msg->rip_nets;
3846920Ssam 		}
3856920Ssam 		n->rip_dst = rt->rt_dst;
3866929Ssam 		n->rip_metric = min(rt->rt_metric + 1, HOPCNT_INFINITY);
3876929Ssam 		n++;
3886920Ssam 	}
3896920Ssam 	if (doinghost) {
3906920Ssam 		doinghost = 0;
3916920Ssam 		base = nethash;
3926920Ssam 		goto again;
3936920Ssam 	}
3946929Ssam 	if (n != msg->rip_nets)
395*7139Ssam 		(*output)(sto, dst, (char *)n - packet);
3966920Ssam }
3976920Ssam 
3986920Ssam /*
3996920Ssam  * Handle an incoming routing packet.
4006920Ssam  */
4016920Ssam rip_input(from, size)
4026920Ssam 	struct sockaddr *from;
4036920Ssam 	int size;
4046920Ssam {
4056920Ssam 	struct rt_entry *rt;
4066920Ssam 	struct netinfo *n;
4077133Swnj 	struct ifnet *ifp;
4087133Swnj 	time_t t;
409*7139Ssam 	int newsize;
410*7139Ssam 	struct afswitch *afp;
4116920Ssam 
412*7139Ssam 	if (trace) {
413*7139Ssam 		if (msg->rip_cmd < RIPCMD_MAX)
414*7139Ssam 			printf("%s from %x\n", ripcmds[msg->rip_cmd],
415*7139Ssam 			    ((struct sockaddr_in *)from)->sin_addr);
416*7139Ssam 		else
417*7139Ssam 			printf("%x from %x\n", msg->rip_cmd,
418*7139Ssam 			    ((struct sockaddr_in *)from)->sin_addr);
419*7139Ssam 	}
420*7139Ssam 	if (from->sa_family >= AF_MAX)
421*7139Ssam 		return;
422*7139Ssam 	afp = &afswitch[from->sa_family];
4236937Ssam 	switch (msg->rip_cmd) {
4246937Ssam 
425*7139Ssam 	case RIPCMD_REQUEST:
426*7139Ssam 		newsize = 0;
427*7139Ssam 		size -= 4 * sizeof (char);
428*7139Ssam 		n = msg->rip_nets;
429*7139Ssam 		while (size > 0) {
430*7139Ssam 			if (size < sizeof (struct netinfo))
431*7139Ssam 				break;
432*7139Ssam 			size -= sizeof (struct netinfo);
4336920Ssam 
434*7139Ssam 			/*
435*7139Ssam 			 * A single entry with sa_family == AF_UNSPEC and
436*7139Ssam 			 * metric ``infinity'' means ``all routes''.
437*7139Ssam 			 */
438*7139Ssam 			if (n->rip_dst.sa_family == AF_UNSPEC &&
439*7139Ssam 			    n->rip_metric == HOPCNT_INFINITY && size == 0) {
440*7139Ssam 				supply(from, 0);	/* don't route */
441*7139Ssam 				return;
442*7139Ssam 			}
443*7139Ssam 			rt = rtlookup(&n->rip_dst);
444*7139Ssam 			n->rip_metric = rt == 0 ? HOPCNT_INFINITY :
445*7139Ssam 				min(rt->rt_metric+1, HOPCNT_INFINITY);
446*7139Ssam 			n++, newsize += sizeof (struct netinfo);
447*7139Ssam 		}
448*7139Ssam 		if (newsize > 0) {
449*7139Ssam 			msg->rip_cmd = RIPCMD_RESPONSE;
450*7139Ssam 			newsize += sizeof (int);
451*7139Ssam 			(*afp->af_output)(s, from, newsize);
452*7139Ssam 		}
4536920Ssam 		return;
4546937Ssam 
4557029Ssam 	case RIPCMD_TRACEON:
456*7139Ssam 		if ((*afp->af_portcheck)(from) == 0)
4577029Ssam 			return;
4587133Swnj 		if (trace)
4597133Swnj 			return;
4607133Swnj 		packet[size] = '\0';
4617133Swnj 		ftrace = fopen(msg->rip_tracefile, "a");
4627133Swnj 		if (ftrace == NULL)
4637133Swnj 			return;
4647133Swnj 		(void) dup2(fileno(ftrace), 1);
4657133Swnj 		(void) dup2(fileno(ftrace), 2);
4667133Swnj 		trace = 1;
4677133Swnj 		t = time(0);
4687133Swnj 		printf("*** Tracing turned on at %.24s ***\n", ctime(&t));
4697029Ssam 		return;
4707029Ssam 
4717133Swnj 	case RIPCMD_TRACEOFF:
4727133Swnj 		/* verify message came from a priviledged port */
473*7139Ssam 		if ((*afp->af_portcheck)(from) == 0)
4746937Ssam 			return;
4757029Ssam 		if (!trace)
4767029Ssam 			return;
4777029Ssam 		t = time(0);
4787029Ssam 		printf("*** Tracing turned off at %.24s ***\n", ctime(&t));
4797029Ssam 		fflush(stdout), fflush(stderr);
4807029Ssam 		if (ftrace)
4817029Ssam 			fclose(ftrace);
4827029Ssam 		(void) close(1), (void) close(2);
4837029Ssam 		trace = 0;
4847029Ssam 		return;
4857133Swnj 
4867133Swnj 	case RIPCMD_RESPONSE:
4877133Swnj 		/* verify message came from a router */
488*7139Ssam 		if ((*afp->af_portmatch)(from) == 0)
4897133Swnj 			return;
490*7139Ssam 		(*afp->af_canon)(from);
4917133Swnj 		/* are we talking to ourselves? */
4927133Swnj 		ifp = if_ifwithaddr(from);
4937133Swnj 		if (ifp) {
494*7139Ssam 			rt = rtfind(from, 0);
495*7139Ssam 			if (rt == 0) {
4967133Swnj 				addrouteforif(ifp);
497*7139Ssam 				return;
498*7139Ssam 			}
499*7139Ssam 			/* interface previously thought down? */
500*7139Ssam 			if (rt->rt_metric > 0) {
501*7139Ssam 				struct rt_entry *downrt = rtfind(from, 1);
502*7139Ssam 				if (downrt) {
503*7139Ssam 					/* unhide old route and delete other */
504*7139Ssam 					downrt->rt_state &= ~RTS_HIDDEN;
505*7139Ssam 					downrt->rt_state |= RTS_ADDRT;
506*7139Ssam 					rt->rt_state |= RTS_DELRT;
507*7139Ssam 					log("unhide", downrt);
508*7139Ssam 				}
509*7139Ssam 			}
510*7139Ssam 			rt->rt_timer = 0;
5117133Swnj 			return;
5127133Swnj 		}
5137133Swnj 		size -= 4 * sizeof (char);
5147133Swnj 		n = msg->rip_nets;
5157133Swnj 		for (; size > 0; size -= sizeof (struct netinfo), n++) {
5167133Swnj 			if (size < sizeof (struct netinfo))
5177133Swnj 				break;
5187133Swnj 			if (n->rip_metric >= HOPCNT_INFINITY)
5197133Swnj 				continue;
5207133Swnj 			tprintf("dst %x hc %d...",
5217133Swnj 			    ((struct sockaddr_in *)&n->rip_dst)->sin_addr,
5227133Swnj 			    n->rip_metric);
5237133Swnj 			rt = rtlookup(&n->rip_dst);
5247133Swnj 			if (rt == 0) {
5257133Swnj 				rtadd(&n->rip_dst, from, n->rip_metric, 0);
5267133Swnj 				continue;
5277133Swnj 			}
5287133Swnj 			tprintf("ours: gate %x hc %d timer %d\n",
5297133Swnj 			  ((struct sockaddr_in *)&rt->rt_router)->sin_addr,
5307133Swnj 			  rt->rt_metric, rt->rt_timer);
531*7139Ssam 
5327133Swnj 			/*
533*7139Ssam 			 * update if from gateway, shorter, or getting
534*7139Ssam 			 * stale and equivalent.
5357133Swnj 			 */
5367133Swnj 			if (equal(from, &rt->rt_router) ||
5377133Swnj 			    n->rip_metric < rt->rt_metric ||
5387133Swnj 			    (rt->rt_timer > (EXPIRE_TIME/2) &&
5397133Swnj 			    rt->rt_metric == n->rip_metric)) {
5407133Swnj 				rtchange(rt, from, n->rip_metric);
5417133Swnj 				rt->rt_timer = 0;
5427133Swnj 			}
5437133Swnj 		}
5447133Swnj 		return;
5457029Ssam 	}
546*7139Ssam 	printf("bad packet, cmd=%x\n", msg->rip_cmd);
5477029Ssam }
5487029Ssam 
5496920Ssam struct rt_entry *
5506920Ssam rtlookup(dst)
5516920Ssam 	struct sockaddr *dst;
5526920Ssam {
5536920Ssam 	register struct rt_entry *rt;
5546934Ssam 	register struct rthash *rh;
5557011Ssam 	register int hash;
5566920Ssam 	struct afhash h;
5577011Ssam 	int doinghost = 1;
5586920Ssam 
5597011Ssam 	if (dst->sa_family >= AF_MAX)
5607011Ssam 		return (0);
5617011Ssam 	(*afswitch[dst->sa_family].af_hash)(dst, &h);
5627011Ssam 	hash = h.afh_hosthash;
5637011Ssam 	rh = &hosthash[hash % ROUTEHASHSIZ];
5647011Ssam again:
5657011Ssam 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
566*7139Ssam 		if (rt->rt_hash != hash || (rt->rt_state & RTS_HIDDEN))
5677011Ssam 			continue;
5687011Ssam 		if (equal(&rt->rt_dst, dst))
5697011Ssam 			return (rt);
5707011Ssam 	}
5717011Ssam 	if (doinghost) {
5727011Ssam 		doinghost = 0;
5737011Ssam 		hash = h.afh_nethash;
5747011Ssam 		rh = &nethash[hash % ROUTEHASHSIZ];
5757011Ssam 		goto again;
5767011Ssam 	}
5777011Ssam 	return (0);
5787011Ssam }
5797011Ssam 
5807011Ssam struct rt_entry *
581*7139Ssam rtfind(dst, lookfordownif)
5827011Ssam 	struct sockaddr *dst;
583*7139Ssam 	int lookfordownif;
5847011Ssam {
5857011Ssam 	register struct rt_entry *rt;
5867011Ssam 	register struct rthash *rh;
5877011Ssam 	register int hash;
5887011Ssam 	struct afhash h;
5897011Ssam 	int af = dst->sa_family;
5907011Ssam 	int doinghost = 1, (*match)();
5917011Ssam 
5926920Ssam 	if (af >= AF_MAX)
5936920Ssam 		return (0);
5946920Ssam 	(*afswitch[af].af_hash)(dst, &h);
5956920Ssam 	hash = h.afh_hosthash;
5966920Ssam 	rh = &hosthash[hash % ROUTEHASHSIZ];
5976920Ssam 
5986920Ssam again:
5996920Ssam 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
6006920Ssam 		if (rt->rt_hash != hash)
6016920Ssam 			continue;
602*7139Ssam 		if (lookfordownif ^ (rt->rt_state & RTS_HIDDEN))
603*7139Ssam 			continue;
6046920Ssam 		if (doinghost) {
6056920Ssam 			if (equal(&rt->rt_dst, dst))
6066920Ssam 				return (rt);
6076920Ssam 		} else {
6086920Ssam 			if (rt->rt_dst.sa_family == af &&
6096920Ssam 			    (*match)(&rt->rt_dst, dst))
6106920Ssam 				return (rt);
6116920Ssam 		}
6126920Ssam 	}
6136920Ssam 	if (doinghost) {
6146920Ssam 		doinghost = 0;
6156920Ssam 		hash = h.afh_nethash;
6167011Ssam 		rh = &nethash[hash % ROUTEHASHSIZ];
6176920Ssam 		match = afswitch[af].af_netmatch;
6186920Ssam 		goto again;
6196920Ssam 	}
6206920Ssam 	return (0);
6216920Ssam }
6226920Ssam 
623*7139Ssam rtadd(dst, gate, metric, state)
6246920Ssam 	struct sockaddr *dst, *gate;
625*7139Ssam 	int metric, state;
6266920Ssam {
6276920Ssam 	struct afhash h;
6286920Ssam 	register struct rt_entry *rt;
6296934Ssam 	struct rthash *rh;
6306920Ssam 	int af = dst->sa_family, flags, hash;
6316920Ssam 
6326920Ssam 	if (af >= AF_MAX)
6336920Ssam 		return;
6346920Ssam 	(*afswitch[af].af_hash)(dst, &h);
6356920Ssam 	flags = (*afswitch[af].af_checkhost)(dst) ? RTF_HOST : 0;
6366920Ssam 	if (flags & RTF_HOST) {
6376920Ssam 		hash = h.afh_hosthash;
6386920Ssam 		rh = &hosthash[hash % ROUTEHASHSIZ];
6396920Ssam 	} else {
6406920Ssam 		hash = h.afh_nethash;
6416920Ssam 		rh = &nethash[hash % ROUTEHASHSIZ];
6426920Ssam 	}
6436920Ssam 	rt = (struct rt_entry *)malloc(sizeof (*rt));
6446920Ssam 	if (rt == 0)
6456920Ssam 		return;
6466920Ssam 	rt->rt_hash = hash;
6476920Ssam 	rt->rt_dst = *dst;
6487130Swnj 	rt->rt_router = *gate;
6496920Ssam 	rt->rt_metric = metric;
6506920Ssam 	rt->rt_timer = 0;
651*7139Ssam 	rt->rt_flags = RTF_UP | flags;
652*7139Ssam 	rt->rt_state = state;
6537130Swnj 	rt->rt_ifp = if_ifwithnet(&rt->rt_router);
6547130Swnj 	if (metric)
6557130Swnj 		rt->rt_flags |= RTF_GATEWAY;
6566920Ssam 	insque(rt, rh);
6576929Ssam 	log("add", rt);
6587130Swnj 	if (install)
6596937Ssam 		rt->rt_state |= RTS_ADDRT;
6606920Ssam }
6616920Ssam 
6626920Ssam rtchange(rt, gate, metric)
6636920Ssam 	struct rt_entry *rt;
6646920Ssam 	struct sockaddr *gate;
6656920Ssam 	short metric;
6666920Ssam {
667*7139Ssam 	int doioctl = 0, metricchanged = 0;
6686920Ssam 
6697130Swnj 	if (!equal(&rt->rt_router, gate)) {
670*7139Ssam 		if (rt->rt_state & RTS_DONTDELETE) {
671*7139Ssam 			rtadd(&rt->rt_dst, gate, metric,
672*7139Ssam 			   rt->rt_state &~ (RTS_DONTDELETE|RTS_DONTROUTE));
673*7139Ssam 			rt->rt_state |= RTS_DELRT;
674*7139Ssam 			return;
675*7139Ssam 		}
676*7139Ssam 		doioctl++;
6776920Ssam 	}
6786920Ssam 	if (metric != rt->rt_metric) {
679*7139Ssam 		metricchanged++;
6806920Ssam 		rt->rt_metric = metric;
6816920Ssam 	}
682*7139Ssam 	if (doioctl) {
683*7139Ssam 		if ((rt->rt_state & RTS_CHGRT) == 0)
684*7139Ssam 			rt->rt_oldrouter = rt->rt_router;
685*7139Ssam 		rt->rt_router = *gate;
6866937Ssam 		rt->rt_state |= RTS_CHGRT;
687*7139Ssam 	}
688*7139Ssam 	if (doioctl || metricchanged)
689*7139Ssam 		log("change", rt);
6906920Ssam }
6916920Ssam 
6926920Ssam rtdelete(rt)
6936920Ssam 	struct rt_entry *rt;
6946920Ssam {
6957133Swnj 
6966929Ssam 	log("delete", rt);
6977130Swnj 	if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
6987130Swnj 		perror("SIOCDELRT");
699*7139Ssam 	if (rt->rt_state & RTS_DONTDELETE) {
700*7139Ssam 		rt->rt_state |= RTS_HIDDEN;
7017130Swnj 		return;
702*7139Ssam 	}
7036920Ssam 	remque(rt);
7046920Ssam 	free((char *)rt);
7056920Ssam }
7066920Ssam 
7076920Ssam log(operation, rt)
7086920Ssam 	char *operation;
7096920Ssam 	struct rt_entry *rt;
7106920Ssam {
7116920Ssam 	struct sockaddr_in *dst, *gate;
7126937Ssam 	static struct bits {
7136920Ssam 		int	t_bits;
7146920Ssam 		char	*t_name;
7156937Ssam 	} flagbits[] = {
7166920Ssam 		{ RTF_UP,	"UP" },
7177130Swnj 		{ RTF_GATEWAY,	"GATEWAY" },
7186920Ssam 		{ RTF_HOST,	"HOST" },
7196920Ssam 		{ 0 }
7206937Ssam 	}, statebits[] = {
721*7139Ssam 		{ RTS_ADDRT,	"ADD" },
7226937Ssam 		{ RTS_DELRT,	"DELETE" },
7236937Ssam 		{ RTS_CHGRT,	"CHANGE" },
7247130Swnj 		{ RTS_PASSIVE,	"PASSIVE" },
725*7139Ssam 		{ RTS_DONTDELETE,"DONTDELETE" },
726*7139Ssam 		{ RTS_DONTROUTE,"DONTROUTE" },
727*7139Ssam 		{ RTS_HIDDEN,	"HIDDEN" },
7286937Ssam 		{ 0 }
7296920Ssam 	};
7306937Ssam 	register struct bits *p;
7316920Ssam 	register int first;
7326920Ssam 	char *cp;
7336920Ssam 
7346929Ssam 	if (trace == 0)
7356929Ssam 		return;
7366920Ssam 	printf("%s ", operation);
7376920Ssam 	dst = (struct sockaddr_in *)&rt->rt_dst;
7387130Swnj 	gate = (struct sockaddr_in *)&rt->rt_router;
739*7139Ssam 	printf("dst %x, router %x", dst->sin_addr, gate->sin_addr);
740*7139Ssam 	if (rt->rt_state & RTS_CHGRT)
741*7139Ssam 		printf(" (old %x)",
742*7139Ssam 			((struct sockaddr_in *)&rt->rt_oldrouter)->sin_addr);
743*7139Ssam 	printf(", metric %d, flags", rt->rt_metric);
7446937Ssam 	cp = " %s";
7456937Ssam 	for (first = 1, p = flagbits; p->t_bits > 0; p++) {
7466920Ssam 		if ((rt->rt_flags & p->t_bits) == 0)
7476920Ssam 			continue;
7486920Ssam 		printf(cp, p->t_name);
7496920Ssam 		if (first) {
7506920Ssam 			cp = "|%s";
7516920Ssam 			first = 0;
7526920Ssam 		}
7536920Ssam 	}
7546937Ssam 	printf(" state");
7556937Ssam 	cp = " %s";
7566937Ssam 	for (first = 1, p = statebits; p->t_bits > 0; p++) {
7576937Ssam 		if ((rt->rt_state & p->t_bits) == 0)
7586937Ssam 			continue;
7596937Ssam 		printf(cp, p->t_name);
7606937Ssam 		if (first) {
7616937Ssam 			cp = "|%s";
7626937Ssam 			first = 0;
7636937Ssam 		}
7646937Ssam 	}
7656920Ssam 	putchar('\n');
7666920Ssam }
7676929Ssam 
7686929Ssam struct ifnet *
7696929Ssam if_ifwithaddr(addr)
7706929Ssam 	struct sockaddr *addr;
7716929Ssam {
7726929Ssam 	register struct ifnet *ifp;
7736929Ssam 
7746929Ssam #define	same(a1, a2) \
7756929Ssam 	(bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0)
7766929Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
7776929Ssam 		if (ifp->if_addr.sa_family != addr->sa_family)
7786929Ssam 			continue;
7796929Ssam 		if (same(&ifp->if_addr, addr))
7806929Ssam 			break;
7816929Ssam 		if ((ifp->if_flags & IFF_BROADCAST) &&
7826929Ssam 		    same(&ifp->if_broadaddr, addr))
7836929Ssam 			break;
7846929Ssam 	}
7856929Ssam 	return (ifp);
7866929Ssam #undef same
7876929Ssam }
7886929Ssam 
7896929Ssam struct ifnet *
7906929Ssam if_ifwithnet(addr)
7916929Ssam 	register struct sockaddr *addr;
7926929Ssam {
7936929Ssam 	register struct ifnet *ifp;
7946929Ssam 	register int af = addr->sa_family;
7956929Ssam 	register int (*netmatch)();
7966929Ssam 
7976929Ssam 	if (af >= AF_MAX)
7986929Ssam 		return (0);
7996929Ssam 	netmatch = afswitch[af].af_netmatch;
8006929Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
8016929Ssam 		if (af != ifp->if_addr.sa_family)
8026929Ssam 			continue;
8036929Ssam 		if ((*netmatch)(addr, &ifp->if_addr))
8046929Ssam 			break;
8056929Ssam 	}
8066929Ssam 	return (ifp);
8076929Ssam }
8086929Ssam 
8096929Ssam struct in_addr
8106929Ssam if_makeaddr(net, host)
8116929Ssam 	int net, host;
8126929Ssam {
8136929Ssam 	u_long addr;
8146929Ssam 
8156929Ssam 	if (net < 128)
8166929Ssam 		addr = (net << 24) | host;
8176929Ssam 	else if (net < 65536)
8186929Ssam 		addr = (net << 16) | host;
8196929Ssam 	else
8206929Ssam 		addr = (net << 8) | host;
8216929Ssam #ifdef vax
8226929Ssam 	addr = htonl(addr);
8236929Ssam #endif
8246929Ssam 	return (*(struct in_addr *)&addr);
8256929Ssam }
826