xref: /csrg-svn/sbin/routed/routed.c (revision 7133)
16920Ssam #ifndef lint
2*7133Swnj static char sccsid[] = "@(#)routed.c	4.14 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>
186920Ssam #include "rip.h"
196920Ssam #include "router.h"
206920Ssam 
216920Ssam #define	LOOPBACKNET	0177
226920Ssam /* casts to keep lint happy */
236920Ssam #define	insque(q,p)	_insque((caddr_t)q,(caddr_t)p)
246920Ssam #define	remque(q)	_remque((caddr_t)q)
256920Ssam #define equal(a1, a2) \
266920Ssam 	(bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof (struct sockaddr)) == 0)
276929Ssam #define	min(a,b)	((a)>(b)?(b):(a))
286920Ssam 
296920Ssam struct nlist nl[] = {
306920Ssam #define	N_IFNET		0
316920Ssam 	{ "_ifnet" },
326920Ssam 	0,
336920Ssam };
346920Ssam 
356920Ssam struct	sockaddr_in myaddr = { AF_INET, IPPORT_ROUTESERVER };
366920Ssam 
376920Ssam int	s;
387130Swnj int	snoroute;		/* socket with no routing */
396929Ssam int	kmem = -1;
40*7133Swnj int	supplier = -1;		/* process should supply updates */
416962Ssam int	install = 1;		/* if 1 call kernel */
42*7133Swnj int	timeval = -TIMER_RATE;
436920Ssam int	timer();
446920Ssam int	cleanup();
45*7133Swnj 
46*7133Swnj #define tprintf if (trace) printf
476920Ssam int	trace = 0;
487029Ssam FILE	*ftrace;
496920Ssam 
50*7133Swnj char	packet[MAXPACKETSIZE+1];
51*7133Swnj struct	rip *msg = (struct rip *)packet;
526920Ssam 
536934Ssam struct in_addr if_makeaddr();
546934Ssam struct ifnet *if_ifwithaddr(), *if_ifwithnet();
556920Ssam extern char *malloc();
566922Ssam extern int errno, exit();
57*7133Swnj char	**argv0;
586920Ssam 
59*7133Swnj int	sndmsg(), supply();
60*7133Swnj 
616920Ssam main(argc, argv)
626920Ssam 	int argc;
636920Ssam 	char *argv[];
646920Ssam {
656920Ssam 	int cc;
666920Ssam 	struct sockaddr from;
676920Ssam 
68*7133Swnj 	argv0 = argv;
697029Ssam #ifndef DEBUG
707029Ssam 	if (fork())
717029Ssam 		exit(0);
727029Ssam 	for (cc = 0; cc < 10; cc++)
737029Ssam 		(void) close(cc);
747029Ssam 	(void) open("/", 0);
757029Ssam 	(void) dup2(0, 1);
767029Ssam 	(void) dup2(0, 2);
777029Ssam 	{ int t = open("/dev/tty", 2);
787029Ssam 	  if (t >= 0) {
797029Ssam 		ioctl(t, TIOCNOTTY, (char *)0);
807029Ssam 		(void) close(t);
817029Ssam 	  }
826920Ssam 	}
837029Ssam #endif
846920Ssam 	if (trace) {
857029Ssam 		ftrace = fopen("/etc/routerlog", "w");
867029Ssam 		dup2(fileno(ftrace), 1);
877029Ssam 		dup2(fileno(ftrace), 2);
886920Ssam 	}
896937Ssam #ifdef vax || pdp11
906920Ssam 	myaddr.sin_port = htons(myaddr.sin_port);
916920Ssam #endif
926920Ssam again:
936920Ssam 	s = socket(SOCK_DGRAM, 0, &myaddr, 0);
946920Ssam 	if (s < 0) {
956920Ssam 		perror("socket");
966920Ssam 		sleep(30);
976920Ssam 		goto again;
986920Ssam 	}
997130Swnj again2:
1007130Swnj 	snoroute = socket(SOCK_DGRAM, 0, 0, SO_DONTROUTE);
1017130Swnj 	if (snoroute < 0) {
1027130Swnj 		perror("socket");
1037130Swnj 		sleep(30);
1047130Swnj 		goto again2;
1057130Swnj 	}
1066920Ssam 	argv++, argc--;
107*7133Swnj 	while (argc > 0 && **argv == '-') {
108*7133Swnj 		if (!strcmp(*argv, "-s") == 0) {
1096929Ssam 			supplier = 1;
110*7133Swnj 			argv++, argc--;
111*7133Swnj 			continue;
112*7133Swnj 		}
113*7133Swnj 		if (!strcmp(*argv, "-q") == 0) {
1146920Ssam 			supplier = 0;
115*7133Swnj 			argv++, argc--;
116*7133Swnj 			continue;
117*7133Swnj 		}
118*7133Swnj 		goto usage;
1196920Ssam 	}
120*7133Swnj 	if (argc > 0) {
121*7133Swnj usage:
122*7133Swnj 		fprintf(stderr, "usage: routed [ -s ]\n");
123*7133Swnj 		exit(1);
124*7133Swnj 	}
125*7133Swnj 	rtinit();
126*7133Swnj 	ifinit();
127*7133Swnj 	if (supplier < 0)
128*7133Swnj 		supplier = 0;
129*7133Swnj 	gwkludge();
130*7133Swnj 	msg->rip_cmd = RIPCMD_REQUEST;
131*7133Swnj 	msg->rip_nets[0].rip_dst.sa_family = AF_UNSPEC;
132*7133Swnj 	msg->rip_nets[0].rip_metric = HOPCNT_INFINITY;
133*7133Swnj 	toall(sendmsg);
1346920Ssam 	sigset(SIGALRM, timer);
1356929Ssam 	timer();
1366920Ssam 
1376920Ssam 	for (;;) {
1386920Ssam 		cc = receive(s, &from, packet, sizeof (packet));
1396920Ssam 		if (cc <= 0) {
1406920Ssam 			if (cc < 0 && errno != EINTR)
1416920Ssam 				perror("receive");
1426920Ssam 			continue;
1436920Ssam 		}
1446920Ssam 		sighold(SIGALRM);
1456920Ssam 		rip_input(&from, cc);
1466920Ssam 		sigrelse(SIGALRM);
1476920Ssam 	}
1486920Ssam }
1496920Ssam 
150*7133Swnj rtinit()
1516920Ssam {
1526934Ssam 	register struct rthash *rh;
1536920Ssam 
154*7133Swnj 	for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
155*7133Swnj 		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
156*7133Swnj 	for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
157*7133Swnj 		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
1586920Ssam }
1596920Ssam 
1606934Ssam struct	ifnet *ifnet;
161*7133Swnj 
162*7133Swnj ifinit()
1636920Ssam {
164*7133Swnj 	struct ifnet *ifp, *next;
1656929Ssam 	register struct sockaddr *dst;
166*7133Swnj 	int uniquemultihostinterfaces = 0;
1676920Ssam 
168*7133Swnj 	nlist("/vmunix", nl);
169*7133Swnj 	if (nl[N_IFNET].n_value == 0) {
170*7133Swnj 		printf("ifnet: not in namelist\n");
171*7133Swnj 		goto bad;
1726920Ssam 	}
173*7133Swnj 	kmem = open("/dev/kmem", 0);
1746920Ssam 	if (kmem < 0) {
175*7133Swnj 		perror("/dev/kmem");
176*7133Swnj 		goto bad;
1776920Ssam 	}
1786929Ssam 	if (lseek(kmem, (long)nl[N_IFNET].n_value, 0) == -1 ||
179*7133Swnj 	    read(kmem, (char *)&next, sizeof (next)) != sizeof (next)) {
180*7133Swnj 		printf("ifnet: error reading kmem\n");
181*7133Swnj 		goto bad;
1826929Ssam 	}
183*7133Swnj 	while (next) {
184*7133Swnj 		ifp = (struct ifnet *)malloc(sizeof (struct ifnet));
185*7133Swnj 		if (ifp == 0) {
186*7133Swnj 			printf("routed: out of memory\n");
1876920Ssam 			break;
1886920Ssam 		}
189*7133Swnj 		if (lseek(kmem, (long)next, 0) == -1 ||
190*7133Swnj 		    read(kmem, (char *)ifp, sizeof (*ifp)) != sizeof (*ifp)) {
191*7133Swnj 			perror("read");
192*7133Swnj 			goto bad;
1936929Ssam 		}
194*7133Swnj 		next = ifp->if_next;
1956929Ssam 		if (ifp->if_addr.sa_family != AF_INET)
196*7133Swnj 			continue;
1976920Ssam 		if (ifp->if_net == LOOPBACKNET)
198*7133Swnj 			continue;
1996929Ssam 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0 ||
2006929Ssam 		    if_ifwithaddr(&ifp->if_dstaddr) == 0)
201*7133Swnj 			uniquemultihostinterfaces++;
2026929Ssam 		ifp->if_next = ifnet;
2036929Ssam 		ifnet = ifp;
204*7133Swnj 		addrouteforif(ifp);
205*7133Swnj 	}
206*7133Swnj 	if (uniquemultihostinterfaces > 1 && supplier < 0)
207*7133Swnj 		supplier = 1;
208*7133Swnj 	return;
209*7133Swnj bad:
210*7133Swnj 	sleep(60);
211*7133Swnj 	execv("/etc/routed", argv0);
212*7133Swnj 	_exit(0177);
213*7133Swnj }
2147130Swnj 
215*7133Swnj addrouteforif(ifp)
216*7133Swnj 	struct ifnet *ifp;
217*7133Swnj {
218*7133Swnj 	struct sockaddr_in net;
219*7133Swnj 	struct sockaddr *dst;
220*7133Swnj 
221*7133Swnj 	if (ifp->if_flags & IFF_POINTOPOINT)
222*7133Swnj 		dst = &ifp->if_dstaddr;
223*7133Swnj 	else {
224*7133Swnj 		bzero((char *)&net, sizeof (net));
225*7133Swnj 		net.sin_family = AF_INET;
226*7133Swnj 		net.sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
227*7133Swnj 		dst = (struct sockaddr *)&net;
2286920Ssam 	}
229*7133Swnj 	rtadd(dst, &ifp->if_addr, 0, RTS_INTERFACE);
2306920Ssam }
2316920Ssam 
232*7133Swnj gwkludge()
2337130Swnj {
2347130Swnj 	struct sockaddr_in dst, gate;
2357130Swnj 	FILE *fp;
2367130Swnj 	struct rt_entry *rt;
237*7133Swnj 	char flags[BUFSIZ];
2387130Swnj 
2397130Swnj 	fp = fopen("/etc/gateways", "r");
2407130Swnj 	if (fp == NULL)
2417130Swnj 		return;
2427130Swnj 	bzero((char *)&dst, sizeof (dst));
2437130Swnj 	bzero((char *)&gate, sizeof (gate));
2447130Swnj 	dst.sin_family = AF_INET;
2457130Swnj 	gate.sin_family = AF_INET;
246*7133Swnj 	for (;;) {
247*7133Swnj 		if (fscanf(fp, "dst %x gateway %x\n", &dst.sin_addr.s_addr,
248*7133Swnj 		   &gate.sin_addr.s_addr, flags) == EOF)
249*7133Swnj 			break;
250*7133Swnj 		rtadd((struct sockaddr *)&dst, (struct sockaddr *)&gate, 1,
251*7133Swnj 		    RTS_GLOBAL|(!strcmp(flags, "passive") ? RTS_PASSIVE : 0));
2527130Swnj 	}
2537130Swnj 	fclose(fp);
2547130Swnj }
2557130Swnj 
256*7133Swnj timer()
2576920Ssam {
2586934Ssam 	register struct rthash *rh;
2596920Ssam 	register struct rt_entry *rt;
2606934Ssam 	struct rthash *base = hosthash;
261*7133Swnj 	int doinghost = 1, state;
2626920Ssam 
263*7133Swnj 	timeval += TIMER_RATE;
264*7133Swnj 	tprintf(">>> time %d >>>\n", timeval);
2656920Ssam again:
266*7133Swnj 	for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
267*7133Swnj 		rt = rh->rt_forw;
268*7133Swnj 		for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
269*7133Swnj 			if (!(rt->rt_state & RTS_GLOBAL))
270*7133Swnj 				rt->rt_timer += TIMER_RATE;
271*7133Swnj 			log("", rt);
272*7133Swnj 			if (rt->rt_timer >= EXPIRE_TIME)
273*7133Swnj 				rt->rt_metric = HOPCNT_INFINITY;
274*7133Swnj 			if ((rt->rt_state & RTS_DELRT) ||
275*7133Swnj 			    rt->rt_timer >= GARBAGE_TIME) {
276*7133Swnj 				if (rt->rt_state&(RTS_INTERFACE|RTS_GLOBAL)) {
277*7133Swnj 					if (rt->rt_timer > 9999)
278*7133Swnj 						rt->rt_timer = 9999;
279*7133Swnj 					continue;
280*7133Swnj 				}
281*7133Swnj 				rt = rt->rt_back;
282*7133Swnj 				rtdelete(rt->rt_forw);
283*7133Swnj 				continue;
284*7133Swnj 			}
285*7133Swnj 			state = rt->rt_state;
286*7133Swnj 			if (rt->rt_state & RTS_ADDRT) {
287*7133Swnj 				if (ioctl(s, SIOCADDRT,(char *)&rt->rt_rt) < 0)
288*7133Swnj 					perror("SIOCADDRT");
289*7133Swnj 				rt->rt_state &= ~RTS_ADDRT;
290*7133Swnj 			}
291*7133Swnj 			if (rt->rt_state & RTS_CHGRT) {
292*7133Swnj 				struct rtentry oldroute;
293*7133Swnj 
294*7133Swnj 				oldroute = rt->rt_rt;
295*7133Swnj 				rt->rt_router = rt->rt_newrouter;
296*7133Swnj 				if (ioctl(s, SIOCADDRT,(char *)&rt->rt_rt) < 0)
297*7133Swnj 					perror("SIOCADDRT");
298*7133Swnj 				if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
299*7133Swnj 					perror("SIOCDELRT");
300*7133Swnj 				rt->rt_state &= ~RTS_CHGRT;
301*7133Swnj 			}
302*7133Swnj 			if (supplier && (state & (RTS_CHGRT|RTS_ADDRT))) {
303*7133Swnj 				log("broadcast", rt);
304*7133Swnj 				msg->rip_cmd = RIPCMD_RESPONSE;
305*7133Swnj 				msg->rip_nets[0].rip_dst = rt->rt_dst;
306*7133Swnj 				msg->rip_nets[0].rip_metric =
307*7133Swnj 				    min(rt->rt_metric+1, HOPCNT_INFINITY);
308*7133Swnj 				sendmsgtoall();
309*7133Swnj 			}
310*7133Swnj 		}
3116920Ssam 	}
3126920Ssam 	if (doinghost) {
313*7133Swnj 		doinghost = 0;
3146929Ssam 		base = nethash;
3156920Ssam 		goto again;
3166920Ssam 	}
317*7133Swnj 	if (supplier && (timeval % SUPPLY_INTERVAL) == 0)
318*7133Swnj 		toall(supply);
319*7133Swnj 	tprintf("<<< time %d <<<\n", timeval);
320*7133Swnj 	alarm(TIMER_RATE);
3216920Ssam }
3226920Ssam 
323*7133Swnj toall(f)
324*7133Swnj 	int (*f)();
3256920Ssam {
326*7133Swnj 	register struct rthash *rh;
3276920Ssam 	register struct rt_entry *rt;
3286920Ssam 	register struct sockaddr *dst;
3296934Ssam 	struct rthash *base = hosthash;
3306920Ssam 	int doinghost = 1;
3316920Ssam 
3326920Ssam again:
3336920Ssam 	for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
3346920Ssam 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
335*7133Swnj 		if ((rt->rt_state&RTS_PASSIVE) || rt->rt_metric > 0)
3366920Ssam 			continue;
3376920Ssam 		if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST))
3386920Ssam 			dst = &rt->rt_ifp->if_broadaddr;
3396920Ssam 		else
3407130Swnj 			dst = &rt->rt_router;
341*7133Swnj 		(*f)(rt, dst);
3426920Ssam 	}
3436920Ssam 	if (doinghost) {
3446920Ssam 		base = nethash;
3456920Ssam 		doinghost = 0;
3466920Ssam 		goto again;
3476920Ssam 	}
3486920Ssam }
3496920Ssam 
350*7133Swnj sendmsg(rt, dst)
351*7133Swnj 	register struct rt_entry *rt;
352*7133Swnj 	struct sockaddr *dst;
353*7133Swnj {
354*7133Swnj 
355*7133Swnj 	(*afswitch[dst->sa_family].af_output)(s, dst, sizeof (struct rip));
356*7133Swnj }
357*7133Swnj 
358*7133Swnj supply(rt, sa)
359*7133Swnj 	register struct rt_entry *rt;
3606920Ssam 	struct sockaddr *sa;
3616920Ssam {
3626920Ssam 	struct netinfo *n = msg->rip_nets;
3636934Ssam 	register struct rthash *rh;
3646934Ssam 	struct rthash *base = hosthash;
3656929Ssam 	int doinghost = 1, size;
3666920Ssam 	int (*output)() = afswitch[sa->sa_family].af_output;
367*7133Swnj 	int sto = (rt->rt_state&RTS_INTERFACE) ? snoroute : s;
3686920Ssam 
369*7133Swnj 	log("supply", rt);
3706920Ssam 	msg->rip_cmd = RIPCMD_RESPONSE;
3716920Ssam again:
3726920Ssam 	for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
3736920Ssam 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
3746929Ssam 		size = (char *)n - packet;
3756929Ssam 		if (size > MAXPACKETSIZE - sizeof (struct netinfo)) {
376*7133Swnj 			(*output)(sto, sa, size);
3776920Ssam 			n = msg->rip_nets;
3786920Ssam 		}
3796920Ssam 		n->rip_dst = rt->rt_dst;
3806929Ssam 		n->rip_metric = min(rt->rt_metric + 1, HOPCNT_INFINITY);
3816929Ssam 		n++;
3826920Ssam 	}
3836920Ssam 	if (doinghost) {
3846920Ssam 		doinghost = 0;
3856920Ssam 		base = nethash;
3866920Ssam 		goto again;
3876920Ssam 	}
3886929Ssam 	if (n != msg->rip_nets)
389*7133Swnj 		(*output)(sto, sa, (char *)n - packet);
3906920Ssam }
3916920Ssam 
3926920Ssam /*
3936920Ssam  * Respond to a routing info request.
3946920Ssam  */
3956920Ssam rip_respond(from, size)
3966920Ssam 	struct sockaddr *from;
3976920Ssam 	int size;
3986920Ssam {
3996920Ssam 	struct netinfo *np = msg->rip_nets;
4006920Ssam 	struct rt_entry *rt;
4016920Ssam 	int newsize = 0;
4026920Ssam 
4036929Ssam 	size -= 4 * sizeof (char);
4046920Ssam 	while (size > 0) {
4056920Ssam 		if (size < sizeof (struct netinfo))
4066920Ssam 			break;
4076920Ssam 		size -= sizeof (struct netinfo);
4086920Ssam 		if (np->rip_dst.sa_family == AF_UNSPEC &&
4096920Ssam 		    np->rip_metric == HOPCNT_INFINITY && size == 0) {
4107130Swnj 			supply(s, from);
4116920Ssam 			return;
4126920Ssam 		}
4136920Ssam 		rt = rtlookup(&np->rip_dst);
4146929Ssam 		np->rip_metric = rt == 0 ?
4156929Ssam 			HOPCNT_INFINITY : min(rt->rt_metric+1, HOPCNT_INFINITY);
4166920Ssam 		np++, newsize += sizeof (struct netinfo);
4176920Ssam 	}
4186920Ssam 	if (newsize > 0) {
4196920Ssam 		msg->rip_cmd = RIPCMD_RESPONSE;
4206920Ssam 		newsize += sizeof (int);
4217130Swnj 		(*afswitch[from->sa_family].af_output)(s, from, newsize);
4226920Ssam 	}
4236920Ssam }
4246920Ssam 
4256920Ssam /*
4266920Ssam  * Handle an incoming routing packet.
4276920Ssam  */
4286920Ssam rip_input(from, size)
4296920Ssam 	struct sockaddr *from;
4306920Ssam 	int size;
4316920Ssam {
4326920Ssam 	struct rt_entry *rt;
4336920Ssam 	struct netinfo *n;
434*7133Swnj 	struct ifnet *ifp;
435*7133Swnj 	time_t t;
4366920Ssam 
4376937Ssam 	switch (msg->rip_cmd) {
4386937Ssam 
4396937Ssam 	default:
4406920Ssam 		return;
4416920Ssam 
4426937Ssam 	case RIPCMD_REQUEST:
4436920Ssam 		rip_respond(from, size);
4446920Ssam 		return;
4456937Ssam 
4467029Ssam 	case RIPCMD_TRACEON:
4477029Ssam 		if ((*afswitch[from->sa_family].af_portcheck)(from) == 0)
4487029Ssam 			return;
449*7133Swnj 		if (trace)
450*7133Swnj 			return;
451*7133Swnj 		packet[size] = '\0';
452*7133Swnj 		ftrace = fopen(msg->rip_tracefile, "a");
453*7133Swnj 		if (ftrace == NULL)
454*7133Swnj 			return;
455*7133Swnj 		(void) dup2(fileno(ftrace), 1);
456*7133Swnj 		(void) dup2(fileno(ftrace), 2);
457*7133Swnj 		trace = 1;
458*7133Swnj 		t = time(0);
459*7133Swnj 		printf("*** Tracing turned on at %.24s ***\n", ctime(&t));
4607029Ssam 		return;
4617029Ssam 
462*7133Swnj 	case RIPCMD_TRACEOFF:
463*7133Swnj 		/* verify message came from a priviledged port */
464*7133Swnj 		if ((*afswitch[from->sa_family].af_portcheck)(from) == 0)
4656937Ssam 			return;
4667029Ssam 		if (!trace)
4677029Ssam 			return;
4687029Ssam 		t = time(0);
4697029Ssam 		printf("*** Tracing turned off at %.24s ***\n", ctime(&t));
4707029Ssam 		fflush(stdout), fflush(stderr);
4717029Ssam 		if (ftrace)
4727029Ssam 			fclose(ftrace);
4737029Ssam 		(void) close(1), (void) close(2);
4747029Ssam 		trace = 0;
4757029Ssam 		return;
476*7133Swnj 
477*7133Swnj 	case RIPCMD_RESPONSE:
478*7133Swnj 		/* verify message came from a router */
479*7133Swnj 		if ((*afswitch[from->sa_family].af_portmatch)(from) == 0)
480*7133Swnj 			return;
481*7133Swnj 		(*afswitch[from->sa_family].af_canon)(from);
482*7133Swnj 		tprintf("input from %x\n",
483*7133Swnj 		    ((struct sockaddr_in *)from)->sin_addr);
484*7133Swnj 		/* are we talking to ourselves? */
485*7133Swnj 		ifp = if_ifwithaddr(from);
486*7133Swnj 		if (ifp) {
487*7133Swnj 			rt = rtfind(from);
488*7133Swnj 			if (rt)
489*7133Swnj 				rt->rt_timer = 0;
490*7133Swnj 			else
491*7133Swnj 				addrouteforif(ifp);
492*7133Swnj 			return;
493*7133Swnj 		}
494*7133Swnj 		size -= 4 * sizeof (char);
495*7133Swnj 		n = msg->rip_nets;
496*7133Swnj 		for (; size > 0; size -= sizeof (struct netinfo), n++) {
497*7133Swnj 			if (size < sizeof (struct netinfo))
498*7133Swnj 				break;
499*7133Swnj 			if (n->rip_metric >= HOPCNT_INFINITY)
500*7133Swnj 				continue;
501*7133Swnj 			tprintf("dst %x hc %d...",
502*7133Swnj 			    ((struct sockaddr_in *)&n->rip_dst)->sin_addr,
503*7133Swnj 			    n->rip_metric);
504*7133Swnj 			rt = rtlookup(&n->rip_dst);
505*7133Swnj 			if (rt == 0) {
506*7133Swnj 				rtadd(&n->rip_dst, from, n->rip_metric, 0);
507*7133Swnj 				tprintf("new\n");
508*7133Swnj 				continue;
509*7133Swnj 			}
510*7133Swnj 			tprintf("ours: gate %x hc %d timer %d\n",
511*7133Swnj 			  ((struct sockaddr_in *)&rt->rt_router)->sin_addr,
512*7133Swnj 			  rt->rt_metric, rt->rt_timer);
513*7133Swnj 			/*
514*7133Swnj 			 * update if from gateway, shorter, or getting stale
515*7133Swnj 			 * and equivalent.
516*7133Swnj 			 */
517*7133Swnj 			if (equal(from, &rt->rt_router) ||
518*7133Swnj 			    n->rip_metric < rt->rt_metric ||
519*7133Swnj 			    (rt->rt_timer > (EXPIRE_TIME/2) &&
520*7133Swnj 			    rt->rt_metric == n->rip_metric)) {
521*7133Swnj 				rtchange(rt, from, n->rip_metric);
522*7133Swnj 				rt->rt_timer = 0;
523*7133Swnj 			}
524*7133Swnj 		}
525*7133Swnj 		return;
5267029Ssam 	}
5277029Ssam }
5287029Ssam 
5296920Ssam struct rt_entry *
5306920Ssam rtlookup(dst)
5316920Ssam 	struct sockaddr *dst;
5326920Ssam {
5336920Ssam 	register struct rt_entry *rt;
5346934Ssam 	register struct rthash *rh;
5357011Ssam 	register int hash;
5366920Ssam 	struct afhash h;
5377011Ssam 	int doinghost = 1;
5386920Ssam 
5397011Ssam 	if (dst->sa_family >= AF_MAX)
5407011Ssam 		return (0);
5417011Ssam 	(*afswitch[dst->sa_family].af_hash)(dst, &h);
5427011Ssam 	hash = h.afh_hosthash;
5437011Ssam 	rh = &hosthash[hash % ROUTEHASHSIZ];
5447011Ssam again:
5457011Ssam 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
5467011Ssam 		if (rt->rt_hash != hash)
5477011Ssam 			continue;
5487011Ssam 		if (equal(&rt->rt_dst, dst))
5497011Ssam 			return (rt);
5507011Ssam 	}
5517011Ssam 	if (doinghost) {
5527011Ssam 		doinghost = 0;
5537011Ssam 		hash = h.afh_nethash;
5547011Ssam 		rh = &nethash[hash % ROUTEHASHSIZ];
5557011Ssam 		goto again;
5567011Ssam 	}
5577011Ssam 	return (0);
5587011Ssam }
5597011Ssam 
5607011Ssam struct rt_entry *
5617011Ssam rtfind(dst)
5627011Ssam 	struct sockaddr *dst;
5637011Ssam {
5647011Ssam 	register struct rt_entry *rt;
5657011Ssam 	register struct rthash *rh;
5667011Ssam 	register int hash;
5677011Ssam 	struct afhash h;
5687011Ssam 	int af = dst->sa_family;
5697011Ssam 	int doinghost = 1, (*match)();
5707011Ssam 
5716920Ssam 	if (af >= AF_MAX)
5726920Ssam 		return (0);
5736920Ssam 	(*afswitch[af].af_hash)(dst, &h);
5746920Ssam 	hash = h.afh_hosthash;
5756920Ssam 	rh = &hosthash[hash % ROUTEHASHSIZ];
5766920Ssam 
5776920Ssam again:
5786920Ssam 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
5796920Ssam 		if (rt->rt_hash != hash)
5806920Ssam 			continue;
5816920Ssam 		if (doinghost) {
5826920Ssam 			if (equal(&rt->rt_dst, dst))
5836920Ssam 				return (rt);
5846920Ssam 		} else {
5856920Ssam 			if (rt->rt_dst.sa_family == af &&
5866920Ssam 			    (*match)(&rt->rt_dst, dst))
5876920Ssam 				return (rt);
5886920Ssam 		}
5896920Ssam 	}
5906920Ssam 	if (doinghost) {
5916920Ssam 		doinghost = 0;
5926920Ssam 		hash = h.afh_nethash;
5937011Ssam 		rh = &nethash[hash % ROUTEHASHSIZ];
5946920Ssam 		match = afswitch[af].af_netmatch;
5956920Ssam 		goto again;
5966920Ssam 	}
5976920Ssam 	return (0);
5986920Ssam }
5996920Ssam 
600*7133Swnj rtadd(dst, gate, metric, iflags)
6016920Ssam 	struct sockaddr *dst, *gate;
602*7133Swnj 	int metric, iflags;
6036920Ssam {
6046920Ssam 	struct afhash h;
6056920Ssam 	register struct rt_entry *rt;
6066934Ssam 	struct rthash *rh;
6076920Ssam 	int af = dst->sa_family, flags, hash;
6086920Ssam 
6096920Ssam 	if (af >= AF_MAX)
6106920Ssam 		return;
6116920Ssam 	(*afswitch[af].af_hash)(dst, &h);
6126920Ssam 	flags = (*afswitch[af].af_checkhost)(dst) ? RTF_HOST : 0;
6136920Ssam 	if (flags & RTF_HOST) {
6146920Ssam 		hash = h.afh_hosthash;
6156920Ssam 		rh = &hosthash[hash % ROUTEHASHSIZ];
6166920Ssam 	} else {
6176920Ssam 		hash = h.afh_nethash;
6186920Ssam 		rh = &nethash[hash % ROUTEHASHSIZ];
6196920Ssam 	}
6206920Ssam 	rt = (struct rt_entry *)malloc(sizeof (*rt));
6216920Ssam 	if (rt == 0)
6226920Ssam 		return;
6236920Ssam 	rt->rt_hash = hash;
6246920Ssam 	rt->rt_dst = *dst;
6257130Swnj 	rt->rt_router = *gate;
6266920Ssam 	rt->rt_metric = metric;
6276920Ssam 	rt->rt_timer = 0;
628*7133Swnj 	rt->rt_flags = RTF_UP | flags | iflags;
6296937Ssam 	rt->rt_state = 0;
6307130Swnj 	rt->rt_ifp = if_ifwithnet(&rt->rt_router);
6317130Swnj 	if (metric)
6327130Swnj 		rt->rt_flags |= RTF_GATEWAY;
6336920Ssam 	insque(rt, rh);
6346929Ssam 	log("add", rt);
6357130Swnj 	if (install)
6366937Ssam 		rt->rt_state |= RTS_ADDRT;
6376920Ssam }
6386920Ssam 
6396920Ssam rtchange(rt, gate, metric)
6406920Ssam 	struct rt_entry *rt;
6416920Ssam 	struct sockaddr *gate;
6426920Ssam 	short metric;
6436920Ssam {
6446920Ssam 	int change = 0;
6456920Ssam 
6467130Swnj 	if (!equal(&rt->rt_router, gate)) {
6477130Swnj 		rt->rt_newrouter = *gate;
6486920Ssam 		change++;
6496920Ssam 	}
6506920Ssam 	if (metric != rt->rt_metric) {
6517130Swnj 		if (metric == 0)
6527130Swnj 			rt->rt_flags |= RTF_GATEWAY;
6536920Ssam 		rt->rt_metric = metric;
6546920Ssam 		change++;
6556920Ssam 	}
6566920Ssam 	if (!change)
6576920Ssam 		return;
6586929Ssam 	log("change", rt);
6597130Swnj 	if (install)
6606937Ssam 		rt->rt_state |= RTS_CHGRT;
6616920Ssam }
6626920Ssam 
6636920Ssam rtdelete(rt)
6646920Ssam 	struct rt_entry *rt;
6656920Ssam {
666*7133Swnj 
6676929Ssam 	log("delete", rt);
6687130Swnj 	if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
6697130Swnj 		perror("SIOCDELRT");
6707130Swnj 	/* don't delete interface entries so we can poll them later */
6717130Swnj 	if (rt->rt_state & RTS_INTERFACE)
6727130Swnj 		return;
6736920Ssam 	remque(rt);
6746920Ssam 	free((char *)rt);
6756920Ssam }
6766920Ssam 
6776920Ssam log(operation, rt)
6786920Ssam 	char *operation;
6796920Ssam 	struct rt_entry *rt;
6806920Ssam {
6816920Ssam 	time_t t = time(0);
6826920Ssam 	struct sockaddr_in *dst, *gate;
6836937Ssam 	static struct bits {
6846920Ssam 		int	t_bits;
6856920Ssam 		char	*t_name;
6866937Ssam 	} flagbits[] = {
6876920Ssam 		{ RTF_UP,	"UP" },
6887130Swnj 		{ RTF_GATEWAY,	"GATEWAY" },
6896920Ssam 		{ RTF_HOST,	"HOST" },
6906920Ssam 		{ 0 }
6916937Ssam 	}, statebits[] = {
6926937Ssam 		{ RTS_DELRT,	"DELETE" },
6936937Ssam 		{ RTS_CHGRT,	"CHANGE" },
6947130Swnj 		{ RTS_PASSIVE,	"PASSIVE" },
6957130Swnj 		{ RTS_INTERFACE,"INTERFACE" },
696*7133Swnj 		{ RTS_GLOBAL,	"GLOBAL" },
6976937Ssam 		{ 0 }
6986920Ssam 	};
6996937Ssam 	register struct bits *p;
7006920Ssam 	register int first;
7016920Ssam 	char *cp;
7026920Ssam 
7036929Ssam 	if (trace == 0)
7046929Ssam 		return;
7056920Ssam 	printf("%s ", operation);
7066920Ssam 	dst = (struct sockaddr_in *)&rt->rt_dst;
7077130Swnj 	gate = (struct sockaddr_in *)&rt->rt_router;
7086937Ssam 	printf("dst %x, router %x, metric %d, flags",
7096920Ssam 		dst->sin_addr, gate->sin_addr, rt->rt_metric);
7106937Ssam 	cp = " %s";
7116937Ssam 	for (first = 1, p = flagbits; p->t_bits > 0; p++) {
7126920Ssam 		if ((rt->rt_flags & p->t_bits) == 0)
7136920Ssam 			continue;
7146920Ssam 		printf(cp, p->t_name);
7156920Ssam 		if (first) {
7166920Ssam 			cp = "|%s";
7176920Ssam 			first = 0;
7186920Ssam 		}
7196920Ssam 	}
7206937Ssam 	printf(" state");
7216937Ssam 	cp = " %s";
7226937Ssam 	for (first = 1, p = statebits; p->t_bits > 0; p++) {
7236937Ssam 		if ((rt->rt_state & p->t_bits) == 0)
7246937Ssam 			continue;
7256937Ssam 		printf(cp, p->t_name);
7266937Ssam 		if (first) {
7276937Ssam 			cp = "|%s";
7286937Ssam 			first = 0;
7296937Ssam 		}
7306937Ssam 	}
7316920Ssam 	putchar('\n');
7326920Ssam }
7336929Ssam 
7346929Ssam struct ifnet *
7356929Ssam if_ifwithaddr(addr)
7366929Ssam 	struct sockaddr *addr;
7376929Ssam {
7386929Ssam 	register struct ifnet *ifp;
7396929Ssam 
7406929Ssam #define	same(a1, a2) \
7416929Ssam 	(bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0)
7426929Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
7436929Ssam 		if (ifp->if_addr.sa_family != addr->sa_family)
7446929Ssam 			continue;
7456929Ssam 		if (same(&ifp->if_addr, addr))
7466929Ssam 			break;
7476929Ssam 		if ((ifp->if_flags & IFF_BROADCAST) &&
7486929Ssam 		    same(&ifp->if_broadaddr, addr))
7496929Ssam 			break;
7506929Ssam 	}
7516929Ssam 	return (ifp);
7526929Ssam #undef same
7536929Ssam }
7546929Ssam 
7556929Ssam struct ifnet *
7566929Ssam if_ifwithnet(addr)
7576929Ssam 	register struct sockaddr *addr;
7586929Ssam {
7596929Ssam 	register struct ifnet *ifp;
7606929Ssam 	register int af = addr->sa_family;
7616929Ssam 	register int (*netmatch)();
7626929Ssam 
7636929Ssam 	if (af >= AF_MAX)
7646929Ssam 		return (0);
7656929Ssam 	netmatch = afswitch[af].af_netmatch;
7666929Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
7676929Ssam 		if (af != ifp->if_addr.sa_family)
7686929Ssam 			continue;
7696929Ssam 		if ((*netmatch)(addr, &ifp->if_addr))
7706929Ssam 			break;
7716929Ssam 	}
7726929Ssam 	return (ifp);
7736929Ssam }
7746929Ssam 
7756929Ssam struct in_addr
7766929Ssam if_makeaddr(net, host)
7776929Ssam 	int net, host;
7786929Ssam {
7796929Ssam 	u_long addr;
7806929Ssam 
7816929Ssam 	if (net < 128)
7826929Ssam 		addr = (net << 24) | host;
7836929Ssam 	else if (net < 65536)
7846929Ssam 		addr = (net << 16) | host;
7856929Ssam 	else
7866929Ssam 		addr = (net << 8) | host;
7876929Ssam #ifdef vax
7886929Ssam 	addr = htonl(addr);
7896929Ssam #endif
7906929Ssam 	return (*(struct in_addr *)&addr);
7916929Ssam }
792